Changeset View
Changeset View
Standalone View
Standalone View
sys/arm/ti/am335x/am335x_ehrpwm.c
Show All 38 Lines | |||||
#include <sys/rman.h> | #include <sys/rman.h> | ||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <dev/ofw/openfirm.h> | #include <dev/ofw/openfirm.h> | ||||
#include <dev/ofw/ofw_bus.h> | #include <dev/ofw/ofw_bus.h> | ||||
#include <dev/ofw/ofw_bus_subr.h> | #include <dev/ofw/ofw_bus_subr.h> | ||||
#include <dev/pwm/pwmc.h> | |||||
#include "pwmbus_if.h" | #include "pwmbus_if.h" | ||||
#include "am335x_pwm.h" | #include "am335x_pwm.h" | ||||
/******************************************************************************* | /******************************************************************************* | ||||
* Enhanced resolution PWM driver. Many of the advanced featues of the hardware | * Enhanced resolution PWM driver. Many of the advanced featues of the hardware | ||||
* are not supported by this driver. What is implemented here is simple | * are not supported by this driver. What is implemented here is simple | ||||
* variable-duty-cycle PWM output. | * variable-duty-cycle PWM output. | ||||
Show All 12 Lines | #define PWM_LOCK_INIT(_sc) mtx_init(&(_sc)->sc_mtx, \ | ||||
device_get_nameunit(_sc->sc_dev), "am335x_ehrpwm softc", MTX_DEF) | device_get_nameunit(_sc->sc_dev), "am335x_ehrpwm softc", MTX_DEF) | ||||
#define PWM_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) | #define PWM_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) | ||||
#define EPWM_READ2(_sc, reg) bus_read_2((_sc)->sc_mem_res, reg) | #define EPWM_READ2(_sc, reg) bus_read_2((_sc)->sc_mem_res, reg) | ||||
#define EPWM_WRITE2(_sc, reg, value) \ | #define EPWM_WRITE2(_sc, reg, value) \ | ||||
bus_write_2((_sc)->sc_mem_res, reg, value) | bus_write_2((_sc)->sc_mem_res, reg, value) | ||||
#define EPWM_TBCTL 0x00 | #define EPWM_TBCTL 0x00 | ||||
/* see 15.2.2.11 for the first two, used in debug situations */ | |||||
#define TBCTL_FREERUN_STOP_NEXT_TBC_INCREMENT (0 << 14) | |||||
#define TBCTL_FREERUN_STOP_COMPLETE_CYCLE (1 << 14) | |||||
/* ignore suspend control signal */ | |||||
#define TBCTL_FREERUN (2 << 14) | #define TBCTL_FREERUN (2 << 14) | ||||
#define TBCTL_PHDIR_UP (1 << 13) | #define TBCTL_PHDIR_UP (1 << 13) | ||||
#define TBCTL_PHDIR_DOWN (0 << 13) | #define TBCTL_PHDIR_DOWN (0 << 13) | ||||
#define TBCTL_CLKDIV(x) ((x) << 10) | #define TBCTL_CLKDIV(x) ((x) << 10) | ||||
#define TBCTL_CLKDIV_MASK (3 << 10) | #define TBCTL_CLKDIV_MASK (3 << 10) | ||||
#define TBCTL_HSPCLKDIV(x) ((x) << 7) | #define TBCTL_HSPCLKDIV(x) ((x) << 7) | ||||
#define TBCTL_HSPCLKDIV_MASK (3 << 7) | #define TBCTL_HSPCLKDIV_MASK (3 << 7) | ||||
#define TBCTL_SYNCOSEL_DISABLED (3 << 4) | #define TBCTL_SYNCOSEL_DISABLED (3 << 4) | ||||
#define TBCTL_PRDLD_SHADOW (0 << 3) | #define TBCTL_PRDLD_SHADOW (0 << 3) | ||||
#define TBCTL_PRDLD_IMMEDIATE (0 << 3) | #define TBCTL_PRDLD_IMMEDIATE (1 << 3) | ||||
#define TBCTL_PHSEN_ENABLED (1 << 2) | |||||
#define TBCTL_PHSEN_DISABLED (0 << 2) | #define TBCTL_PHSEN_DISABLED (0 << 2) | ||||
#define TBCTL_PHSEN_ENABLED (1 << 2) | |||||
#define TBCTL_CTRMODE_MASK (3) | #define TBCTL_CTRMODE_MASK (3) | ||||
#define TBCTL_CTRMODE_UP (0 << 0) | #define TBCTL_CTRMODE_UP (0 << 0) | ||||
#define TBCTL_CTRMODE_DOWN (1 << 0) | #define TBCTL_CTRMODE_DOWN (1 << 0) | ||||
#define TBCTL_CTRMODE_UPDOWN (2 << 0) | #define TBCTL_CTRMODE_UPDOWN (2 << 0) | ||||
#define TBCTL_CTRMODE_FREEZE (3 << 0) | #define TBCTL_CTRMODE_FREEZE (3 << 0) | ||||
#define EPWM_TBSTS 0x02 | #define EPWM_TBSTS 0x02 | ||||
#define EPWM_TBPHSHR 0x04 | #define EPWM_TBPHSHR 0x04 | ||||
Show All 36 Lines | |||||
#define EPWM_AQCSFRC 0x1c | #define EPWM_AQCSFRC 0x1c | ||||
#define AQCSFRC_OFF 0 | #define AQCSFRC_OFF 0 | ||||
#define AQCSFRC_LO 1 | #define AQCSFRC_LO 1 | ||||
#define AQCSFRC_HI 2 | #define AQCSFRC_HI 2 | ||||
#define AQCSFRC_MASK 3 | #define AQCSFRC_MASK 3 | ||||
#define AQCSFRC(chan, hilo) ((hilo) << (2 * chan)) | #define AQCSFRC(chan, hilo) ((hilo) << (2 * chan)) | ||||
/* Trip-Zone module */ | /* Trip-Zone module */ | ||||
#define EPWM_TZSEL 0x24 | |||||
#define EPWM_TZCTL 0x28 | #define EPWM_TZCTL 0x28 | ||||
#define EPWM_TZFLG 0x2C | #define EPWM_TZFLG 0x2C | ||||
/* Dead band */ | |||||
#define EPWM_DBCTL 0x1E | |||||
#define DBCTL_MASK (3 << 0) | |||||
#define DBCTL_BYPASS 0 | |||||
#define DBCTL_RISING_EDGE 1 | |||||
#define DBCTL_FALLING_EDGE 2 | |||||
#define DBCTL_BOTH_EDGE 3 | |||||
/* PWM-chopper */ | |||||
#define EPWM_PCCTL 0x3C | |||||
#define PCCTL_CHPEN_MASK (1 << 0) | |||||
#define PCCTL_CHPEN_DISABLE 0 | |||||
#define PCCTL_CHPEN_ENABLE 1 | |||||
/* High-Resolution PWM */ | /* High-Resolution PWM */ | ||||
#define EPWM_HRCTL 0x40 | #define EPWM_HRCTL 0x40 | ||||
#define HRCTL_DELMODE_BOTH 3 | #define HRCTL_DELMODE_BOTH 3 | ||||
#define HRCTL_DELMODE_FALL 2 | #define HRCTL_DELMODE_FALL 2 | ||||
#define HRCTL_DELMODE_RISE 1 | #define HRCTL_DELMODE_RISE 1 | ||||
static device_probe_t am335x_ehrpwm_probe; | static device_probe_t am335x_ehrpwm_probe; | ||||
static device_attach_t am335x_ehrpwm_attach; | static device_attach_t am335x_ehrpwm_attach; | ||||
▲ Show 20 Lines • Show All 176 Lines • ▼ Show 20 Lines | am335x_ehrpwm_channel_get_config(device_t dev, u_int channel, | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
*period = sc->sc_period; | *period = sc->sc_period; | ||||
*duty = sc->sc_channels[channel].duty; | *duty = sc->sc_channels[channel].duty; | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
am335x_ehrpwm_channel_set_flags(device_t dev, u_int channel, | |||||
uint32_t flags) | |||||
{ | |||||
struct am335x_ehrpwm_softc *sc; | |||||
if (channel >= NUM_CHANNELS) | |||||
return (EINVAL); | |||||
sc = device_get_softc(dev); | |||||
PWM_LOCK(sc); | |||||
if (flags & PWM_POLARITY_INVERTED) { | |||||
sc->sc_channels[channel].inverted = true; | |||||
/* Action-Qualifier 15.2.2.5 */ | |||||
if (channel == 0) | |||||
EPWM_WRITE2(sc, EPWM_AQCTLA, | |||||
(AQCTL_ZRO_CLEAR | AQCTL_CAU_SET)); | |||||
else | |||||
EPWM_WRITE2(sc, EPWM_AQCTLB, | |||||
(AQCTL_ZRO_CLEAR | AQCTL_CBU_SET)); | |||||
} else { | |||||
sc->sc_channels[channel].inverted = false; | |||||
if (channel == 0) | |||||
EPWM_WRITE2(sc, EPWM_AQCTLA, | |||||
(AQCTL_ZRO_SET | AQCTL_CAU_CLEAR)); | |||||
else | |||||
EPWM_WRITE2(sc, EPWM_AQCTLB, | |||||
(AQCTL_ZRO_SET | AQCTL_CBU_CLEAR)); | |||||
} | |||||
PWM_UNLOCK(sc); | |||||
return (0); | |||||
} | |||||
static int | |||||
am335x_ehrpwm_channel_get_flags(device_t dev, u_int channel, | |||||
uint32_t *flags) | |||||
{ | |||||
struct am335x_ehrpwm_softc *sc; | |||||
if (channel >= NUM_CHANNELS) | |||||
return (EINVAL); | |||||
sc = device_get_softc(dev); | |||||
if (sc->sc_channels[channel].inverted == true) | |||||
*flags = PWM_POLARITY_INVERTED; | |||||
else | |||||
*flags = 0; | |||||
return (0); | |||||
} | |||||
static int | |||||
am335x_ehrpwm_channel_enable(device_t dev, u_int channel, bool enable) | am335x_ehrpwm_channel_enable(device_t dev, u_int channel, bool enable) | ||||
{ | { | ||||
struct am335x_ehrpwm_softc *sc; | struct am335x_ehrpwm_softc *sc; | ||||
if (channel >= NUM_CHANNELS) | if (channel >= NUM_CHANNELS) | ||||
return (EINVAL); | return (EINVAL); | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
Show All 34 Lines | am335x_ehrpwm_probe(device_t dev) | ||||
return (BUS_PROBE_DEFAULT); | return (BUS_PROBE_DEFAULT); | ||||
} | } | ||||
static int | static int | ||||
am335x_ehrpwm_attach(device_t dev) | am335x_ehrpwm_attach(device_t dev) | ||||
{ | { | ||||
struct am335x_ehrpwm_softc *sc; | struct am335x_ehrpwm_softc *sc; | ||||
uint32_t reg; | uint16_t reg; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
sc->sc_dev = dev; | sc->sc_dev = dev; | ||||
PWM_LOCK_INIT(sc); | PWM_LOCK_INIT(sc); | ||||
sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | ||||
&sc->sc_mem_rid, RF_ACTIVE); | &sc->sc_mem_rid, RF_ACTIVE); | ||||
if (sc->sc_mem_res == NULL) { | if (sc->sc_mem_res == NULL) { | ||||
device_printf(dev, "cannot allocate memory resources\n"); | device_printf(dev, "cannot allocate memory resources\n"); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
/* CONFIGURE EPWM1 */ | /* CONFIGURE EPWM */ | ||||
reg = EPWM_READ2(sc, EPWM_TBCTL); | reg = EPWM_READ2(sc, EPWM_TBCTL); | ||||
reg &= ~(TBCTL_CLKDIV_MASK | TBCTL_HSPCLKDIV_MASK); | reg &= ~(TBCTL_CLKDIV_MASK | TBCTL_HSPCLKDIV_MASK); | ||||
EPWM_WRITE2(sc, EPWM_TBCTL, reg); | EPWM_WRITE2(sc, EPWM_TBCTL, reg); | ||||
EPWM_WRITE2(sc, EPWM_TBPRD, DEFAULT_PWM_PERIOD - 1); | EPWM_WRITE2(sc, EPWM_TBPRD, DEFAULT_PWM_PERIOD - 1); | ||||
EPWM_WRITE2(sc, EPWM_CMPA, 0); | EPWM_WRITE2(sc, EPWM_CMPA, 0); | ||||
EPWM_WRITE2(sc, EPWM_CMPB, 0); | EPWM_WRITE2(sc, EPWM_CMPB, 0); | ||||
/* Action-Qualifier 15.2.2.5 */ | |||||
EPWM_WRITE2(sc, EPWM_AQCTLA, (AQCTL_ZRO_SET | AQCTL_CAU_CLEAR)); | EPWM_WRITE2(sc, EPWM_AQCTLA, (AQCTL_ZRO_SET | AQCTL_CAU_CLEAR)); | ||||
EPWM_WRITE2(sc, EPWM_AQCTLB, (AQCTL_ZRO_SET | AQCTL_CBU_CLEAR)); | EPWM_WRITE2(sc, EPWM_AQCTLB, (AQCTL_ZRO_SET | AQCTL_CBU_CLEAR)); | ||||
/* Dead band 15.2.2.6 */ | |||||
reg = EPWM_READ2(sc, EPWM_DBCTL); | |||||
reg &= ~DBCTL_MASK; | |||||
reg |= DBCTL_BYPASS; | |||||
EPWM_WRITE2(sc, EPWM_DBCTL, reg); | |||||
/* PWM-chopper described in 15.2.2.7 */ | |||||
/* Acc. TRM used in pulse transformerbased gate drivers | |||||
* to control the power switching-elements | |||||
*/ | |||||
reg = EPWM_READ2(sc, EPWM_PCCTL); | |||||
reg &= ~PCCTL_CHPEN_MASK; | |||||
reg |= PCCTL_CHPEN_DISABLE; | |||||
EPWM_WRITE2(sc, EPWM_PCCTL, PCCTL_CHPEN_DISABLE); | |||||
/* Trip zone are described in 15.2.2.8. | |||||
* Essential its used to detect faults and can be configured | |||||
* to react on such faults.. | |||||
*/ | |||||
/* disable TZn as one-shot / CVC trip source 15.2.4.18 */ | |||||
EPWM_WRITE2(sc, EPWM_TZSEL, 0x0); | |||||
/* reg described in 15.2.4.19 */ | |||||
EPWM_WRITE2(sc, EPWM_TZCTL, 0xf); | |||||
reg = EPWM_READ2(sc, EPWM_TZFLG); | |||||
/* START EPWM */ | /* START EPWM */ | ||||
reg &= ~TBCTL_CTRMODE_MASK; | reg &= ~TBCTL_CTRMODE_MASK; | ||||
reg |= TBCTL_CTRMODE_UP | TBCTL_FREERUN; | reg |= TBCTL_CTRMODE_UP | TBCTL_FREERUN; | ||||
EPWM_WRITE2(sc, EPWM_TBCTL, reg); | EPWM_WRITE2(sc, EPWM_TBCTL, reg); | ||||
EPWM_WRITE2(sc, EPWM_TZCTL, 0xf); | |||||
reg = EPWM_READ2(sc, EPWM_TZFLG); | |||||
if ((sc->sc_busdev = device_add_child(dev, "pwmbus", -1)) == NULL) { | if ((sc->sc_busdev = device_add_child(dev, "pwmbus", -1)) == NULL) { | ||||
device_printf(dev, "Cannot add child pwmbus\n"); | device_printf(dev, "Cannot add child pwmbus\n"); | ||||
// This driver can still do things even without the bus child. | // This driver can still do things even without the bus child. | ||||
} | } | ||||
bus_generic_probe(dev); | bus_generic_probe(dev); | ||||
return (bus_generic_attach(dev)); | return (bus_generic_attach(dev)); | ||||
fail: | fail: | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | static device_method_t am335x_ehrpwm_methods[] = { | ||||
/* ofw_bus_if */ | /* ofw_bus_if */ | ||||
DEVMETHOD(ofw_bus_get_node, am335x_ehrpwm_get_node), | DEVMETHOD(ofw_bus_get_node, am335x_ehrpwm_get_node), | ||||
/* pwm interface */ | /* pwm interface */ | ||||
DEVMETHOD(pwmbus_channel_count, am335x_ehrpwm_channel_count), | DEVMETHOD(pwmbus_channel_count, am335x_ehrpwm_channel_count), | ||||
DEVMETHOD(pwmbus_channel_config, am335x_ehrpwm_channel_config), | DEVMETHOD(pwmbus_channel_config, am335x_ehrpwm_channel_config), | ||||
DEVMETHOD(pwmbus_channel_get_config, am335x_ehrpwm_channel_get_config), | DEVMETHOD(pwmbus_channel_get_config, am335x_ehrpwm_channel_get_config), | ||||
DEVMETHOD(pwmbus_channel_set_flags, am335x_ehrpwm_channel_set_flags), | |||||
DEVMETHOD(pwmbus_channel_get_flags, am335x_ehrpwm_channel_get_flags), | |||||
DEVMETHOD(pwmbus_channel_enable, am335x_ehrpwm_channel_enable), | DEVMETHOD(pwmbus_channel_enable, am335x_ehrpwm_channel_enable), | ||||
DEVMETHOD(pwmbus_channel_is_enabled, am335x_ehrpwm_channel_is_enabled), | DEVMETHOD(pwmbus_channel_is_enabled, am335x_ehrpwm_channel_is_enabled), | ||||
DEVMETHOD_END | DEVMETHOD_END | ||||
}; | }; | ||||
static driver_t am335x_ehrpwm_driver = { | static driver_t am335x_ehrpwm_driver = { | ||||
"pwm", | "pwm", | ||||
Show All 10 Lines |