2 * Copyright (c) 2013 Oleksandr Tymoshenko <gonzo@freebsd.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/limits.h>
36 #include <sys/module.h>
37 #include <sys/mutex.h>
38 #include <sys/resource.h>
41 #include <machine/bus.h>
43 #include <dev/ofw/openfirm.h>
44 #include <dev/ofw/ofw_bus.h>
45 #include <dev/ofw/ofw_bus_subr.h>
47 #include <dev/pwm/pwmc.h>
49 #include "pwmbus_if.h"
51 #include "am335x_pwm.h"
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 ******************************************************************************/
60 #define DEFAULT_PWM_PERIOD 1000
61 #define PWM_CLOCK 100000000UL
63 #define NS_PER_SEC 1000000000
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)
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)
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)
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)
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
142 #define AQCSFRC_MASK 3
143 #define AQCSFRC(chan, hilo) ((hilo) << (2 * chan))
145 /* Trip-Zone module */
146 #define EPWM_TZSEL 0x24
147 #define EPWM_TZCTL 0x28
148 #define EPWM_TZFLG 0x2C
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
159 #define EPWM_PCCTL 0x3C
160 #define PCCTL_CHPEN_MASK (1 << 0)
161 #define PCCTL_CHPEN_DISABLE 0
162 #define PCCTL_CHPEN_ENABLE 1
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
170 static device_probe_t am335x_ehrpwm_probe;
171 static device_attach_t am335x_ehrpwm_attach;
172 static device_detach_t am335x_ehrpwm_detach;
174 struct ehrpwm_channel {
175 u_int duty; /* on duration, in ns */
176 bool enabled; /* channel enabled? */
177 bool inverted; /* signal inverted? */
179 #define NUM_CHANNELS 2
181 struct am335x_ehrpwm_softc {
185 struct resource *sc_mem_res;
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];
195 static struct ofw_compat_data compat_data[] = {
196 {"ti,am33xx-ehrpwm", true},
199 SIMPLEBUS_PNP_INFO(compat_data);
202 am335x_ehrpwm_cfg_duty(struct am335x_ehrpwm_softc *sc, u_int chan, u_int duty)
209 tbcmp = max(1, duty / sc->sc_clktick);
211 sc->sc_channels[chan].duty = tbcmp * sc->sc_clktick;
214 EPWM_WRITE2(sc, (chan == 0) ? EPWM_CMPA : EPWM_CMPB, tbcmp);
218 am335x_ehrpwm_cfg_enable(struct am335x_ehrpwm_softc *sc, u_int chan, bool enable)
222 sc->sc_channels[chan].enabled = enable;
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.
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);
235 regval |= AQCSFRC(chan, AQCSFRC_LO);
237 EPWM_WRITE2(sc, EPWM_AQCSFRC, regval);
241 am335x_ehrpwm_cfg_period(struct am335x_ehrpwm_softc *sc, u_int period)
244 u_int clkdiv, hspclkdiv, pwmclk, pwmtick, tbprd;
246 /* Can't do a period shorter than 2 clock ticks. */
247 if (period < 2 * NS_PER_SEC / PWM_CLOCK) {
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.
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;
274 /* Handle requested period too long for available clock divisors. */
279 * If anything has changed from the current settings, reprogram the
280 * clock divisors and period register.
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;
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);
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);
301 * If the period changed, that invalidates the current CMP
302 * registers (duty values), just zero them out.
304 am335x_ehrpwm_cfg_duty(sc, 0, 0);
305 am335x_ehrpwm_cfg_duty(sc, 1, 0);
312 am335x_ehrpwm_channel_count(device_t dev, u_int *nchannel)
315 *nchannel = NUM_CHANNELS;
321 am335x_ehrpwm_channel_config(device_t dev, u_int channel, u_int period, u_int duty)
323 struct am335x_ehrpwm_softc *sc;
326 if (channel >= NUM_CHANNELS)
329 sc = device_get_softc(dev);
332 status = am335x_ehrpwm_cfg_period(sc, period);
334 am335x_ehrpwm_cfg_duty(sc, channel, duty);
337 return (status ? 0 : EINVAL);
341 am335x_ehrpwm_channel_get_config(device_t dev, u_int channel,
342 u_int *period, u_int *duty)
344 struct am335x_ehrpwm_softc *sc;
346 if (channel >= NUM_CHANNELS)
349 sc = device_get_softc(dev);
350 *period = sc->sc_period;
351 *duty = sc->sc_channels[channel].duty;
356 am335x_ehrpwm_channel_set_flags(device_t dev, u_int channel,
359 struct am335x_ehrpwm_softc *sc;
361 if (channel >= NUM_CHANNELS)
364 sc = device_get_softc(dev);
367 if (flags & PWM_POLARITY_INVERTED) {
368 sc->sc_channels[channel].inverted = true;
369 /* Action-Qualifier 15.2.2.5 */
371 EPWM_WRITE2(sc, EPWM_AQCTLA,
372 (AQCTL_ZRO_CLEAR | AQCTL_CAU_SET));
374 EPWM_WRITE2(sc, EPWM_AQCTLB,
375 (AQCTL_ZRO_CLEAR | AQCTL_CBU_SET));
377 sc->sc_channels[channel].inverted = false;
379 EPWM_WRITE2(sc, EPWM_AQCTLA,
380 (AQCTL_ZRO_SET | AQCTL_CAU_CLEAR));
382 EPWM_WRITE2(sc, EPWM_AQCTLB,
383 (AQCTL_ZRO_SET | AQCTL_CBU_CLEAR));
391 am335x_ehrpwm_channel_get_flags(device_t dev, u_int channel,
394 struct am335x_ehrpwm_softc *sc;
395 if (channel >= NUM_CHANNELS)
398 sc = device_get_softc(dev);
400 if (sc->sc_channels[channel].inverted == true)
401 *flags = PWM_POLARITY_INVERTED;
410 am335x_ehrpwm_channel_enable(device_t dev, u_int channel, bool enable)
412 struct am335x_ehrpwm_softc *sc;
414 if (channel >= NUM_CHANNELS)
417 sc = device_get_softc(dev);
420 am335x_ehrpwm_cfg_enable(sc, channel, enable);
427 am335x_ehrpwm_channel_is_enabled(device_t dev, u_int channel, bool *enabled)
429 struct am335x_ehrpwm_softc *sc;
431 if (channel >= NUM_CHANNELS)
434 sc = device_get_softc(dev);
436 *enabled = sc->sc_channels[channel].enabled;
442 am335x_ehrpwm_probe(device_t dev)
445 if (!ofw_bus_status_okay(dev))
448 if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
451 device_set_desc(dev, "AM335x EHRPWM");
453 return (BUS_PROBE_DEFAULT);
457 am335x_ehrpwm_attach(device_t dev)
459 struct am335x_ehrpwm_softc *sc;
462 sc = device_get_softc(dev);
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");
475 reg = EPWM_READ2(sc, EPWM_TBCTL);
476 reg &= ~(TBCTL_CLKDIV_MASK | TBCTL_HSPCLKDIV_MASK);
477 EPWM_WRITE2(sc, EPWM_TBCTL, reg);
479 EPWM_WRITE2(sc, EPWM_TBPRD, DEFAULT_PWM_PERIOD - 1);
480 EPWM_WRITE2(sc, EPWM_CMPA, 0);
481 EPWM_WRITE2(sc, EPWM_CMPB, 0);
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));
487 /* Dead band 15.2.2.6 */
488 reg = EPWM_READ2(sc, EPWM_DBCTL);
491 EPWM_WRITE2(sc, EPWM_DBCTL, reg);
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
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);
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..
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);
513 reg &= ~TBCTL_CTRMODE_MASK;
514 reg |= TBCTL_CTRMODE_UP | TBCTL_FREERUN;
515 EPWM_WRITE2(sc, EPWM_TBCTL, reg);
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.
522 bus_generic_probe(dev);
523 return (bus_generic_attach(dev));
525 PWM_LOCK_DESTROY(sc);
527 bus_release_resource(dev, SYS_RES_MEMORY,
528 sc->sc_mem_rid, sc->sc_mem_res);
534 am335x_ehrpwm_detach(device_t dev)
536 struct am335x_ehrpwm_softc *sc;
539 sc = device_get_softc(dev);
541 if ((error = bus_generic_detach(sc->sc_dev)) != 0)
546 if (sc->sc_busdev != NULL)
547 device_delete_child(dev, sc->sc_busdev);
550 bus_release_resource(dev, SYS_RES_MEMORY,
551 sc->sc_mem_rid, sc->sc_mem_res);
555 PWM_LOCK_DESTROY(sc);
561 am335x_ehrpwm_get_node(device_t bus, device_t dev)
565 * Share our controller node with our pwmbus child; it instantiates
566 * devices by walking the children contained within our node.
568 return ofw_bus_get_node(bus);
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),
577 DEVMETHOD(ofw_bus_get_node, am335x_ehrpwm_get_node),
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),
591 static driver_t am335x_ehrpwm_driver = {
593 am335x_ehrpwm_methods,
594 sizeof(struct am335x_ehrpwm_softc),
597 static devclass_t am335x_ehrpwm_devclass;
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);