svn commit: r252722 - head/sys/arm/ti/am335x

Oleksandr Tymoshenko gonzo at FreeBSD.org
Thu Jul 4 20:13:23 UTC 2013


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);


More information about the svn-src-all mailing list