Author: gonzo
Date: Thu Jul  4 20:13:22 2013
New Revision: 252722
URL: http://svnweb.freebsd.org/changeset/base/252722

Log:
  Add support for ePWM submodule of PWMSS
  
  ePWM is controlled by sysctl nodes dev.am335x_pwm.N.period,
  dev.am335x_pwm.N.dutyA and dev.am335x_pwm.N.dutyB that controls
  PWM period and duty cycles for channels A and B respectively.
  
  Period and duty cycle are measured in clock ticks. Default
  clock frequency for AM335x PWM subsystem is 100MHz

Modified:
  head/sys/arm/ti/am335x/am335x_pwm.c

Modified: head/sys/arm/ti/am335x/am335x_pwm.c
==============================================================================
--- head/sys/arm/ti/am335x/am335x_pwm.c Thu Jul  4 20:12:12 2013        
(r252721)
+++ head/sys/arm/ti/am335x/am335x_pwm.c Thu Jul  4 20:13:22 2013        
(r252722)
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/mutex.h>
 #include <sys/resource.h>
 #include <sys/rman.h>
+#include <sys/sysctl.h>
 
 #include <machine/bus.h>
 
@@ -50,6 +51,9 @@ __FBSDID("$FreeBSD$");
 #include "am335x_pwm.h"
 #include "am335x_scm.h"
 
+/* In ticks */
+#define        DEFAULT_PWM_PERIOD      1000
+
 #define        PWM_LOCK(_sc)           mtx_lock(&(_sc)->sc_mtx)
 #define        PWM_UNLOCK(_sc)         mtx_unlock(&(_sc)->sc_mtx)
 #define        PWM_LOCK_INIT(_sc)      mtx_init(&(_sc)->sc_mtx, \
@@ -96,15 +100,24 @@ static struct resource_spec am335x_pwm_m
 #define                ECCTL2_TSCTRSTOP_FREERUN        (1 << 4)
 
 #define        EPWM_TBCTL              0x00
+#define                TBCTL_FREERUN           (2 << 14)
 #define                TBCTL_PHDIR_UP          (1 << 13)
 #define                TBCTL_PHDIR_DOWN        (0 << 13)
 #define                TBCTL_CLKDIV(x)         ((x) << 10)
+#define                TBCTL_CLKDIV_MASK       (3 << 10)
 #define                TBCTL_HSPCLKDIV(x)      ((x) << 7)
+#define                TBCTL_HSPCLKDIV_MASK    (3 << 7)
 #define                TBCTL_SYNCOSEL_DISABLED (3 << 4)
 #define                TBCTL_PRDLD_SHADOW      (0 << 3)
 #define                TBCTL_PRDLD_IMMEDIATE   (0 << 3)
 #define                TBCTL_PHSEN_ENABLED     (1 << 2)
 #define                TBCTL_PHSEN_DISABLED    (0 << 2)
+#define                TBCTL_CTRMODE_MASK      (3)
+#define                TBCTL_CTRMODE_UP        (0 << 0)
+#define                TBCTL_CTRMODE_DOWN      (1 << 0)
+#define                TBCTL_CTRMODE_UPDOWN    (2 << 0)
+#define                TBCTL_CTRMODE_FREEZE    (3 << 0)
+
 #define        EPWM_TBSTS              0x02
 #define        EPWM_TBPHSHR            0x04
 #define        EPWM_TBPHS              0x06
@@ -130,10 +143,14 @@ static struct resource_spec am335x_pwm_m
 /* CMPCTL_LOADAMODE_ZERO */
 #define        EPWM_AQCTLA             0x16
 #define        EPWM_AQCTLB             0x18
-#define                AQCTL_CAU_NONE          (0 << 0)
-#define                AQCTL_CAU_CLEAR         (1 << 0)
-#define                AQCTL_CAU_SET           (2 << 0)
-#define                AQCTL_CAU_TOGGLE        (3 << 0)
+#define                AQCTL_CBU_NONE          (0 << 8)
+#define                AQCTL_CBU_CLEAR         (1 << 8)
+#define                AQCTL_CBU_SET           (2 << 8)
+#define                AQCTL_CBU_TOGGLE        (3 << 8)
+#define                AQCTL_CAU_NONE          (0 << 4)
+#define                AQCTL_CAU_CLEAR         (1 << 4)
+#define                AQCTL_CAU_SET           (2 << 4)
+#define                AQCTL_CAU_TOGGLE        (3 << 4)
 #define                AQCTL_ZRO_NONE          (0 << 0)
 #define                AQCTL_ZRO_CLEAR         (1 << 0)
 #define                AQCTL_ZRO_SET           (2 << 0)
@@ -141,6 +158,15 @@ static struct resource_spec am335x_pwm_m
 #define        EPWM_AQSFRC             0x1a
 #define        EPWM_AQCSFRC            0x1c
 
+/* Trip-Zone module */
+#define        EPWM_TZCTL              0x28
+#define        EPWM_TZFLG              0x2C
+/* High-Resolution PWM */
+#define        EPWM_HRCTL              0x40
+#define                HRCTL_DELMODE_BOTH      3
+#define                HRCTL_DELMODE_FALL      2
+#define                HRCTL_DELMODE_RISE      1
+
 static device_probe_t am335x_pwm_probe;
 static device_attach_t am335x_pwm_attach;
 static device_detach_t am335x_pwm_detach;
@@ -150,6 +176,13 @@ struct am335x_pwm_softc {
        struct mtx              sc_mtx;
        struct resource         *sc_mem_res[4];
        int                     sc_id;
+       /* sysctl for configuration */
+       struct sysctl_oid       *sc_period_oid;
+       struct sysctl_oid       *sc_chanA_oid;
+       struct sysctl_oid       *sc_chanB_oid;
+       uint32_t                sc_pwm_period;
+       uint32_t                sc_pwm_dutyA;
+       uint32_t                sc_pwm_dutyB;
 };
 
 static device_method_t am335x_pwm_methods[] = {
@@ -209,6 +242,71 @@ am335x_pwm_config_ecas(int unit, int per
 }
 
 static int
+am335x_pwm_sysctl_duty(SYSCTL_HANDLER_ARGS)
+{
+       struct am335x_pwm_softc *sc = (struct am335x_pwm_softc*)arg1;
+       int error;
+       uint32_t duty;
+       
+       if (oidp == sc->sc_chanA_oid)
+               duty = sc->sc_pwm_dutyA;
+       else
+               duty = sc->sc_pwm_dutyB;
+       error = sysctl_handle_int(oidp, &duty, 0, req);
+
+       if (error != 0 || req->newptr == NULL)
+               return (error);
+
+       if (duty > sc->sc_pwm_period) {
+               device_printf(sc->sc_dev, "Duty cycle can't be greater then 
period\n");
+               return (EINVAL);
+       }
+
+       PWM_LOCK(sc);
+       if (oidp == sc->sc_chanA_oid) {
+               sc->sc_pwm_dutyA = duty;
+               EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA);
+       }
+       else {
+               sc->sc_pwm_dutyB = duty;
+               EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB);
+       }
+       PWM_UNLOCK(sc);
+
+       return (error);
+}
+
+static int
+am335x_pwm_sysctl_period(SYSCTL_HANDLER_ARGS)
+{
+       struct am335x_pwm_softc *sc = (struct am335x_pwm_softc*)arg1;
+       int error;
+       uint32_t period;
+       
+       period = sc->sc_pwm_period;
+       error = sysctl_handle_int(oidp, &period, 0, req);
+
+       if (error != 0 || req->newptr == NULL)
+               return (error);
+
+       if (period < 1)
+               return (EINVAL);
+
+       if ((period < sc->sc_pwm_dutyA) || (period < sc->sc_pwm_dutyB)) {
+               device_printf(sc->sc_dev, "Period can't be less then duty 
cycle\n");
+               return (EINVAL);
+       }
+
+
+       PWM_LOCK(sc);
+       sc->sc_pwm_period = period;
+       EPWM_WRITE2(sc, EPWM_TBPRD, period - 1);
+       PWM_UNLOCK(sc);
+
+       return (error);
+}
+
+static int
 am335x_pwm_probe(device_t dev)
 {
        if (!ofw_bus_is_compatible(dev, "ti,am335x-pwm"))
@@ -227,6 +325,8 @@ am335x_pwm_attach(device_t dev)
        uint32_t reg;
        phandle_t node;
        pcell_t did;
+       struct sysctl_ctx_list *ctx;
+       struct sysctl_oid *tree;
 
        sc = device_get_softc(dev);
        sc->sc_dev = dev;
@@ -252,6 +352,47 @@ am335x_pwm_attach(device_t dev)
        reg |= (1 << sc->sc_id);
        ti_scm_reg_write_4(SCM_PWMSS_CTRL, reg);
 
+       /* Init backlight interface */
+       ctx = device_get_sysctl_ctx(sc->sc_dev);
+       tree = device_get_sysctl_tree(sc->sc_dev);
+
+       sc->sc_period_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), 
OID_AUTO,
+           "period", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+           am335x_pwm_sysctl_period, "I", "PWM period");
+
+       sc->sc_chanA_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+           "dutyA", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+           am335x_pwm_sysctl_duty, "I", "Channel A duty cycles");
+
+       sc->sc_chanB_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+           "dutyB", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+           am335x_pwm_sysctl_duty, "I", "Channel B duty cycles");
+
+
+       /* CONFIGURE EPWM1 */
+       reg = EPWM_READ2(sc, EPWM_TBCTL);
+       reg &= ~(TBCTL_CLKDIV_MASK | TBCTL_HSPCLKDIV_MASK);
+       EPWM_WRITE2(sc, EPWM_TBCTL, reg);
+
+       sc->sc_pwm_period = DEFAULT_PWM_PERIOD;
+       sc->sc_pwm_dutyA = 0;
+       sc->sc_pwm_dutyB = 0;
+
+       EPWM_WRITE2(sc, EPWM_TBPRD, sc->sc_pwm_period - 1);
+       EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA);
+       EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB);
+
+       EPWM_WRITE2(sc, EPWM_AQCTLA, (AQCTL_ZRO_SET | AQCTL_CAU_CLEAR));
+       EPWM_WRITE2(sc, EPWM_AQCTLB, (AQCTL_ZRO_SET | AQCTL_CBU_CLEAR));
+
+       /* START EPWM */
+       reg &= ~TBCTL_CTRMODE_MASK;
+       reg |= TBCTL_CTRMODE_UP | TBCTL_FREERUN;
+       EPWM_WRITE2(sc, EPWM_TBCTL, reg);
+
+       EPWM_WRITE2(sc, EPWM_TZCTL, 0xf);
+       reg = EPWM_READ2(sc, EPWM_TZFLG);
+
        return (0);
 fail:
        PWM_LOCK_DESTROY(sc);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to