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 #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 "am335x_pwm.h" 50 51 /* In ticks */ 52 #define DEFAULT_PWM_PERIOD 1000 53 #define PWM_CLOCK 100000000UL 54 55 #define PWM_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 56 #define PWM_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 57 #define PWM_LOCK_INIT(_sc) mtx_init(&(_sc)->sc_mtx, \ 58 device_get_nameunit(_sc->sc_dev), "am335x_ehrpwm softc", MTX_DEF) 59 #define PWM_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) 60 61 #define EPWM_READ2(_sc, reg) bus_read_2((_sc)->sc_mem_res, reg); 62 #define EPWM_WRITE2(_sc, reg, value) \ 63 bus_write_2((_sc)->sc_mem_res, reg, value); 64 65 #define EPWM_TBCTL 0x00 66 #define TBCTL_FREERUN (2 << 14) 67 #define TBCTL_PHDIR_UP (1 << 13) 68 #define TBCTL_PHDIR_DOWN (0 << 13) 69 #define TBCTL_CLKDIV(x) ((x) << 10) 70 #define TBCTL_CLKDIV_MASK (3 << 10) 71 #define TBCTL_HSPCLKDIV(x) ((x) << 7) 72 #define TBCTL_HSPCLKDIV_MASK (3 << 7) 73 #define TBCTL_SYNCOSEL_DISABLED (3 << 4) 74 #define TBCTL_PRDLD_SHADOW (0 << 3) 75 #define TBCTL_PRDLD_IMMEDIATE (0 << 3) 76 #define TBCTL_PHSEN_ENABLED (1 << 2) 77 #define TBCTL_PHSEN_DISABLED (0 << 2) 78 #define TBCTL_CTRMODE_MASK (3) 79 #define TBCTL_CTRMODE_UP (0 << 0) 80 #define TBCTL_CTRMODE_DOWN (1 << 0) 81 #define TBCTL_CTRMODE_UPDOWN (2 << 0) 82 #define TBCTL_CTRMODE_FREEZE (3 << 0) 83 84 #define EPWM_TBSTS 0x02 85 #define EPWM_TBPHSHR 0x04 86 #define EPWM_TBPHS 0x06 87 #define EPWM_TBCNT 0x08 88 #define EPWM_TBPRD 0x0a 89 /* Counter-compare */ 90 #define EPWM_CMPCTL 0x0e 91 #define CMPCTL_SHDWBMODE_SHADOW (1 << 6) 92 #define CMPCTL_SHDWBMODE_IMMEDIATE (0 << 6) 93 #define CMPCTL_SHDWAMODE_SHADOW (1 << 4) 94 #define CMPCTL_SHDWAMODE_IMMEDIATE (0 << 4) 95 #define CMPCTL_LOADBMODE_ZERO (0 << 2) 96 #define CMPCTL_LOADBMODE_PRD (1 << 2) 97 #define CMPCTL_LOADBMODE_EITHER (2 << 2) 98 #define CMPCTL_LOADBMODE_FREEZE (3 << 2) 99 #define CMPCTL_LOADAMODE_ZERO (0 << 0) 100 #define CMPCTL_LOADAMODE_PRD (1 << 0) 101 #define CMPCTL_LOADAMODE_EITHER (2 << 0) 102 #define CMPCTL_LOADAMODE_FREEZE (3 << 0) 103 #define EPWM_CMPAHR 0x10 104 #define EPWM_CMPA 0x12 105 #define EPWM_CMPB 0x14 106 /* CMPCTL_LOADAMODE_ZERO */ 107 #define EPWM_AQCTLA 0x16 108 #define EPWM_AQCTLB 0x18 109 #define AQCTL_CBU_NONE (0 << 8) 110 #define AQCTL_CBU_CLEAR (1 << 8) 111 #define AQCTL_CBU_SET (2 << 8) 112 #define AQCTL_CBU_TOGGLE (3 << 8) 113 #define AQCTL_CAU_NONE (0 << 4) 114 #define AQCTL_CAU_CLEAR (1 << 4) 115 #define AQCTL_CAU_SET (2 << 4) 116 #define AQCTL_CAU_TOGGLE (3 << 4) 117 #define AQCTL_ZRO_NONE (0 << 0) 118 #define AQCTL_ZRO_CLEAR (1 << 0) 119 #define AQCTL_ZRO_SET (2 << 0) 120 #define AQCTL_ZRO_TOGGLE (3 << 0) 121 #define EPWM_AQSFRC 0x1a 122 #define EPWM_AQCSFRC 0x1c 123 124 /* Trip-Zone module */ 125 #define EPWM_TZCTL 0x28 126 #define EPWM_TZFLG 0x2C 127 /* High-Resolution PWM */ 128 #define EPWM_HRCTL 0x40 129 #define HRCTL_DELMODE_BOTH 3 130 #define HRCTL_DELMODE_FALL 2 131 #define HRCTL_DELMODE_RISE 1 132 133 static device_probe_t am335x_ehrpwm_probe; 134 static device_attach_t am335x_ehrpwm_attach; 135 static device_detach_t am335x_ehrpwm_detach; 136 137 static int am335x_ehrpwm_clkdiv[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; 138 139 struct am335x_ehrpwm_softc { 140 device_t sc_dev; 141 struct mtx sc_mtx; 142 struct resource *sc_mem_res; 143 int sc_mem_rid; 144 /* sysctl for configuration */ 145 int sc_pwm_clkdiv; 146 int sc_pwm_freq; 147 struct sysctl_oid *sc_clkdiv_oid; 148 struct sysctl_oid *sc_freq_oid; 149 struct sysctl_oid *sc_period_oid; 150 struct sysctl_oid *sc_chanA_oid; 151 struct sysctl_oid *sc_chanB_oid; 152 uint32_t sc_pwm_period; 153 uint32_t sc_pwm_dutyA; 154 uint32_t sc_pwm_dutyB; 155 }; 156 157 static device_method_t am335x_ehrpwm_methods[] = { 158 DEVMETHOD(device_probe, am335x_ehrpwm_probe), 159 DEVMETHOD(device_attach, am335x_ehrpwm_attach), 160 DEVMETHOD(device_detach, am335x_ehrpwm_detach), 161 162 DEVMETHOD_END 163 }; 164 165 static driver_t am335x_ehrpwm_driver = { 166 "am335x_ehrpwm", 167 am335x_ehrpwm_methods, 168 sizeof(struct am335x_ehrpwm_softc), 169 }; 170 171 static devclass_t am335x_ehrpwm_devclass; 172 173 static void 174 am335x_ehrpwm_freq(struct am335x_ehrpwm_softc *sc) 175 { 176 int clkdiv; 177 178 clkdiv = am335x_ehrpwm_clkdiv[sc->sc_pwm_clkdiv]; 179 sc->sc_pwm_freq = PWM_CLOCK / (1 * clkdiv) / sc->sc_pwm_period; 180 } 181 182 static int 183 am335x_ehrpwm_sysctl_freq(SYSCTL_HANDLER_ARGS) 184 { 185 int clkdiv, error, freq, i, period; 186 struct am335x_ehrpwm_softc *sc; 187 uint32_t reg; 188 189 sc = (struct am335x_ehrpwm_softc *)arg1; 190 191 PWM_LOCK(sc); 192 freq = sc->sc_pwm_freq; 193 PWM_UNLOCK(sc); 194 195 error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); 196 if (error != 0 || req->newptr == NULL) 197 return (error); 198 199 if (freq > PWM_CLOCK) 200 freq = PWM_CLOCK; 201 202 PWM_LOCK(sc); 203 if (freq != sc->sc_pwm_freq) { 204 for (i = nitems(am335x_ehrpwm_clkdiv) - 1; i >= 0; i--) { 205 clkdiv = am335x_ehrpwm_clkdiv[i]; 206 period = PWM_CLOCK / clkdiv / freq; 207 if (period > USHRT_MAX) 208 break; 209 sc->sc_pwm_clkdiv = i; 210 sc->sc_pwm_period = period; 211 } 212 /* Reset the duty cycle settings. */ 213 sc->sc_pwm_dutyA = 0; 214 sc->sc_pwm_dutyB = 0; 215 EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA); 216 EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB); 217 /* Update the clkdiv settings. */ 218 reg = EPWM_READ2(sc, EPWM_TBCTL); 219 reg &= ~TBCTL_CLKDIV_MASK; 220 reg |= TBCTL_CLKDIV(sc->sc_pwm_clkdiv); 221 EPWM_WRITE2(sc, EPWM_TBCTL, reg); 222 /* Update the period settings. */ 223 EPWM_WRITE2(sc, EPWM_TBPRD, sc->sc_pwm_period - 1); 224 am335x_ehrpwm_freq(sc); 225 } 226 PWM_UNLOCK(sc); 227 228 return (0); 229 } 230 231 static int 232 am335x_ehrpwm_sysctl_clkdiv(SYSCTL_HANDLER_ARGS) 233 { 234 int error, i, clkdiv; 235 struct am335x_ehrpwm_softc *sc; 236 uint32_t reg; 237 238 sc = (struct am335x_ehrpwm_softc *)arg1; 239 240 PWM_LOCK(sc); 241 clkdiv = am335x_ehrpwm_clkdiv[sc->sc_pwm_clkdiv]; 242 PWM_UNLOCK(sc); 243 244 error = sysctl_handle_int(oidp, &clkdiv, sizeof(clkdiv), req); 245 if (error != 0 || req->newptr == NULL) 246 return (error); 247 248 PWM_LOCK(sc); 249 if (clkdiv != am335x_ehrpwm_clkdiv[sc->sc_pwm_clkdiv]) { 250 for (i = 0; i < nitems(am335x_ehrpwm_clkdiv); i++) 251 if (clkdiv >= am335x_ehrpwm_clkdiv[i]) 252 sc->sc_pwm_clkdiv = i; 253 254 reg = EPWM_READ2(sc, EPWM_TBCTL); 255 reg &= ~TBCTL_CLKDIV_MASK; 256 reg |= TBCTL_CLKDIV(sc->sc_pwm_clkdiv); 257 EPWM_WRITE2(sc, EPWM_TBCTL, reg); 258 am335x_ehrpwm_freq(sc); 259 } 260 PWM_UNLOCK(sc); 261 262 return (0); 263 } 264 265 static int 266 am335x_ehrpwm_sysctl_duty(SYSCTL_HANDLER_ARGS) 267 { 268 struct am335x_ehrpwm_softc *sc = (struct am335x_ehrpwm_softc*)arg1; 269 int error; 270 uint32_t duty; 271 272 if (oidp == sc->sc_chanA_oid) 273 duty = sc->sc_pwm_dutyA; 274 else 275 duty = sc->sc_pwm_dutyB; 276 error = sysctl_handle_int(oidp, &duty, 0, req); 277 278 if (error != 0 || req->newptr == NULL) 279 return (error); 280 281 if (duty > sc->sc_pwm_period) { 282 device_printf(sc->sc_dev, "Duty cycle can't be greater then period\n"); 283 return (EINVAL); 284 } 285 286 PWM_LOCK(sc); 287 if (oidp == sc->sc_chanA_oid) { 288 sc->sc_pwm_dutyA = duty; 289 EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA); 290 } 291 else { 292 sc->sc_pwm_dutyB = duty; 293 EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB); 294 } 295 PWM_UNLOCK(sc); 296 297 return (error); 298 } 299 300 static int 301 am335x_ehrpwm_sysctl_period(SYSCTL_HANDLER_ARGS) 302 { 303 struct am335x_ehrpwm_softc *sc = (struct am335x_ehrpwm_softc*)arg1; 304 int error; 305 uint32_t period; 306 307 period = sc->sc_pwm_period; 308 error = sysctl_handle_int(oidp, &period, 0, req); 309 310 if (error != 0 || req->newptr == NULL) 311 return (error); 312 313 if (period < 1) 314 return (EINVAL); 315 316 if (period > USHRT_MAX) 317 period = USHRT_MAX; 318 319 PWM_LOCK(sc); 320 /* Reset the duty cycle settings. */ 321 sc->sc_pwm_dutyA = 0; 322 sc->sc_pwm_dutyB = 0; 323 EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA); 324 EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB); 325 /* Update the period settings. */ 326 sc->sc_pwm_period = period; 327 EPWM_WRITE2(sc, EPWM_TBPRD, period - 1); 328 am335x_ehrpwm_freq(sc); 329 PWM_UNLOCK(sc); 330 331 return (error); 332 } 333 334 static int 335 am335x_ehrpwm_probe(device_t dev) 336 { 337 338 if (!ofw_bus_status_okay(dev)) 339 return (ENXIO); 340 341 if (!ofw_bus_is_compatible(dev, "ti,am33xx-ehrpwm")) 342 return (ENXIO); 343 344 device_set_desc(dev, "AM335x EHRPWM"); 345 346 return (BUS_PROBE_DEFAULT); 347 } 348 349 static int 350 am335x_ehrpwm_attach(device_t dev) 351 { 352 struct am335x_ehrpwm_softc *sc; 353 uint32_t reg; 354 struct sysctl_ctx_list *ctx; 355 struct sysctl_oid *tree; 356 357 sc = device_get_softc(dev); 358 sc->sc_dev = dev; 359 360 PWM_LOCK_INIT(sc); 361 362 sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 363 &sc->sc_mem_rid, RF_ACTIVE); 364 if (sc->sc_mem_res == NULL) { 365 device_printf(dev, "cannot allocate memory resources\n"); 366 goto fail; 367 } 368 369 /* Init backlight interface */ 370 ctx = device_get_sysctl_ctx(sc->sc_dev); 371 tree = device_get_sysctl_tree(sc->sc_dev); 372 373 sc->sc_clkdiv_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 374 "clkdiv", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 375 am335x_ehrpwm_sysctl_clkdiv, "I", "PWM clock prescaler"); 376 377 sc->sc_freq_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 378 "freq", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 379 am335x_ehrpwm_sysctl_freq, "I", "PWM frequency"); 380 381 sc->sc_period_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 382 "period", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 383 am335x_ehrpwm_sysctl_period, "I", "PWM period"); 384 385 sc->sc_chanA_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 386 "dutyA", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 387 am335x_ehrpwm_sysctl_duty, "I", "Channel A duty cycles"); 388 389 sc->sc_chanB_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 390 "dutyB", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 391 am335x_ehrpwm_sysctl_duty, "I", "Channel B duty cycles"); 392 393 /* CONFIGURE EPWM1 */ 394 reg = EPWM_READ2(sc, EPWM_TBCTL); 395 reg &= ~(TBCTL_CLKDIV_MASK | TBCTL_HSPCLKDIV_MASK); 396 EPWM_WRITE2(sc, EPWM_TBCTL, reg); 397 398 sc->sc_pwm_period = DEFAULT_PWM_PERIOD; 399 sc->sc_pwm_dutyA = 0; 400 sc->sc_pwm_dutyB = 0; 401 am335x_ehrpwm_freq(sc); 402 403 EPWM_WRITE2(sc, EPWM_TBPRD, sc->sc_pwm_period - 1); 404 EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA); 405 EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB); 406 407 EPWM_WRITE2(sc, EPWM_AQCTLA, (AQCTL_ZRO_SET | AQCTL_CAU_CLEAR)); 408 EPWM_WRITE2(sc, EPWM_AQCTLB, (AQCTL_ZRO_SET | AQCTL_CBU_CLEAR)); 409 410 /* START EPWM */ 411 reg &= ~TBCTL_CTRMODE_MASK; 412 reg |= TBCTL_CTRMODE_UP | TBCTL_FREERUN; 413 EPWM_WRITE2(sc, EPWM_TBCTL, reg); 414 415 EPWM_WRITE2(sc, EPWM_TZCTL, 0xf); 416 reg = EPWM_READ2(sc, EPWM_TZFLG); 417 418 return (0); 419 fail: 420 PWM_LOCK_DESTROY(sc); 421 if (sc->sc_mem_res) 422 bus_release_resource(dev, SYS_RES_MEMORY, 423 sc->sc_mem_rid, sc->sc_mem_res); 424 425 return(ENXIO); 426 } 427 428 static int 429 am335x_ehrpwm_detach(device_t dev) 430 { 431 struct am335x_ehrpwm_softc *sc; 432 433 sc = device_get_softc(dev); 434 435 PWM_LOCK(sc); 436 if (sc->sc_mem_res) 437 bus_release_resource(dev, SYS_RES_MEMORY, 438 sc->sc_mem_rid, sc->sc_mem_res); 439 PWM_UNLOCK(sc); 440 441 PWM_LOCK_DESTROY(sc); 442 443 return (0); 444 } 445 446 DRIVER_MODULE(am335x_ehrpwm, am335x_pwmss, am335x_ehrpwm_driver, am335x_ehrpwm_devclass, 0, 0); 447 MODULE_VERSION(am335x_ehrpwm, 1); 448 MODULE_DEPEND(am335x_ehrpwm, am335x_pwmss, 1, 1, 1); 449