Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F134556907
D15769.id43636.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D15769.id43636.diff
View Options
Index: sys/arm/broadcom/bcm2835/bcm2835_pwm.c
===================================================================
--- sys/arm/broadcom/bcm2835/bcm2835_pwm.c
+++ sys/arm/broadcom/bcm2835/bcm2835_pwm.c
@@ -63,11 +63,13 @@
device_t clkman;
- uint32_t freq;
- uint32_t period;
+ uint32_t freq; /* shared between channels 1 and 2 */
+ uint32_t period; /* channel 1 */
uint32_t ratio;
uint32_t mode;
-
+ uint32_t period2; /* channel 2 */
+ uint32_t ratio2;
+ uint32_t mode2;
};
#define BCM_PWM_MEM_WRITE(_sc, _off, _val) \
@@ -87,11 +89,15 @@
#define R_RNG(_sc) BCM_PWM_MEM_READ(_sc, 0x10)
#define W_DAT(_sc, _val) BCM_PWM_MEM_WRITE(_sc, 0x14, _val)
#define R_DAT(_sc) BCM_PWM_MEM_READ(_sc, 0x14)
+#define W_RNG2(_sc, _val) BCM_PWM_MEM_WRITE(_sc, 0x20, _val)
+#define R_RNG2(_sc) BCM_PWM_MEM_READ(_sc, 0x20)
+#define W_DAT2(_sc, _val) BCM_PWM_MEM_WRITE(_sc, 0x24, _val)
+#define R_DAT2(_sc) BCM_PWM_MEM_READ(_sc, 0x24)
static int
bcm_pwm_reconf(struct bcm_pwm_softc *sc)
{
- uint32_t u;
+ uint32_t u, ctlr;
/* Disable PWM */
W_CTL(sc, 0);
@@ -99,25 +105,77 @@
/* Stop PWM clock */
(void)bcm2835_clkman_set_frequency(sc->clkman, BCM_PWM_CLKSRC, 0);
- if (sc->mode == 0)
- return (0);
+ ctlr = 0; /* pre-assign zero, enable bits, write to CTL at end */
+
+ if (sc->mode == 0 && sc->mode2 == 0) /* both modes are zero */
+ return 0; /* device is now off - return */
+ /* set the PWM clock frequency */
+ /* TODO: should I only do this if it changes and not stop it first? */
u = bcm2835_clkman_set_frequency(sc->clkman, BCM_PWM_CLKSRC, sc->freq);
if (u == 0)
return (EINVAL);
sc->freq = u;
- /* Config PWM */
- W_RNG(sc, sc->period);
- if (sc->ratio > sc->period)
- sc->ratio = sc->period;
- W_DAT(sc, sc->ratio);
+ /* control register CTL bits:
+ * (from BCM2835 ARM Peripherals manual, section 9.6)
+ *
+ * 15 MSEN2 chan 2 M/S enable; 0 for PWM algo, 1 for M/S transmission
+ * 14 unused; always reads as 0
+ * 13 USEF2 chan 2 use FIFO (0 uses data; 1 uses FIFO)
+ * 12 POLA2 chan 2 invert polarity (0 normal, 1 inverted polarity)
+ * 11 SBIT2 chan 2 'Silence' bit (when not transmitting data)
+ * 10 RPTL2 chan 2 FIFO repeat last data (1 repeats, 0 interrupts)
+ * 9 MODE2 chan 2 PWM/Serializer mode (0 PWM, 1 Serializer)
+ * 8 PWEN2 chan 2 enable (0 disable, 1 enable)
+ * 7 MSEN1 chan 1 M/S enable; 0 for PWM algo, 1 for M/S transmission
+ * 6 CLRF1 chan 1 clear FIFO (set 1 to clear; always reads as 0)
+ * 5 USEF1 chan 1 use FIFO (0 uses data; 1 uses FIFO)
+ * 4 POLA1 chan 1 invert polarity (0 normal, 1 inverted polarity)
+ * 3 SBIT1 chan 1 'Silence' bit (when not transmitting data)
+ * 2 RTPL1 chan 1 FIFO repeat last data (1 repeats, 0 interrupts)
+ * 1 MODE1 chan 1 PWM/Serializer mode (0 PWM, 1 Serializer)
+ * 0 PWMEN1 chan 1 enable (0 disable, 1 enable)
+ *
+ * Notes on M/S enable: when this bit is '1', a simple M/S ratio is used. In short,
+ * the value of 'ratio' is the number of 'on' bits, and the total length of the data is
+ * defined by 'period'. So if 'ratio' is 2500 and 'period' is 10000, then the output
+ * remains 'on' for 2500 clocks, and goes 'off' for the remaining 7500 clocks.
+ * When the M/S enable is '0', a more complicated algorithm effectively 'dithers' the
+ * pulses in order to obtain the desired ratio. For details, see section 9.3 of the
+ * BCM2835 ARM Peripherals manual.
+ */
- /* Start PWM */
- if (sc->mode == 1)
- W_CTL(sc, 0x81);
- else
- W_CTL(sc, 0x1);
+ if (sc->mode != 0) {
+ /* Config PWM Channel 1 */
+ W_RNG(sc, sc->period);
+ if (sc->ratio > sc->period)
+ sc->ratio = sc->period;
+ W_DAT(sc, sc->ratio);
+
+ /* Start PWM Channel 1 */
+ if (sc->mode == 1)
+ ctlr |= 0x81; /* chan 1 enable + chan 1 M/S enable */
+ else
+ ctlr |= 0x1; /* chan 1 enable */
+ }
+
+ if (sc->mode2 != 0) {
+ /* Config PWM Channel 2 */
+ W_RNG2(sc, sc->period2);
+ if (sc->ratio2 > sc->period2)
+ sc->ratio2 = sc->period2;
+ W_DAT2(sc, sc->ratio2);
+
+ /* Start PWM Channel 2 */
+ if (sc->mode2 == 1)
+ ctlr |= 0x8100; /* chan 2 enable + chan 2 M/S enable */
+ else
+ ctlr |= 0x100; /* chan 2 enable */
+ }
+
+ /* write CTL register with updated value */
+ W_CTL(sc, ctlr);
return (0);
}
@@ -138,7 +196,6 @@
return (error);
}
-
static int
bcm_pwm_mode_proc(SYSCTL_HANDLER_ARGS)
{
@@ -203,7 +260,75 @@
if (r > sc->period) // XXX >= ?
return (EINVAL);
sc->ratio = r;
- BCM_PWM_MEM_WRITE(sc, 0x14, sc->ratio);
+/* BCM_PWM_MEM_WRITE(sc, 0x14, sc->ratio); */
+ W_DAT(sc, sc->ratio);
+ return (0);
+}
+
+static int
+bcm_pwm_pwm_freq2_proc(SYSCTL_HANDLER_ARGS)
+{
+ struct bcm_pwm_softc *sc;
+ uint32_t r;
+ int error;
+
+ sc = (struct bcm_pwm_softc *)arg1;
+ if (sc->mode2 == 1)
+ r = sc->freq / sc->period2;
+ else
+ r = 0;
+ error = sysctl_handle_int(oidp, &r, sizeof(r), req);
+ return (error);
+}
+
+static int
+bcm_pwm_mode2_proc(SYSCTL_HANDLER_ARGS)
+{
+ struct bcm_pwm_softc *sc;
+ uint32_t r;
+ int error;
+
+ sc = (struct bcm_pwm_softc *)arg1;
+ r = sc->mode2;
+ error = sysctl_handle_int(oidp, &r, sizeof(r), req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ if (r > 2)
+ return (EINVAL);
+ sc->mode2 = r;
+ return (bcm_pwm_reconf(sc));
+}
+
+static int
+bcm_pwm_period2_proc(SYSCTL_HANDLER_ARGS)
+{
+ struct bcm_pwm_softc *sc;
+ int error;
+
+ sc = (struct bcm_pwm_softc *)arg1;
+ error = sysctl_handle_int(oidp, &sc->period2, sizeof(sc->period2), req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ return (bcm_pwm_reconf(sc));
+}
+
+static int
+bcm_pwm_ratio2_proc(SYSCTL_HANDLER_ARGS)
+{
+ struct bcm_pwm_softc *sc;
+ uint32_t r;
+ int error;
+
+ sc = (struct bcm_pwm_softc *)arg1;
+ r = sc->ratio2;
+ error = sysctl_handle_int(oidp, &r, sizeof(r), req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ if (r > sc->period2) // XXX >= ?
+ return (EINVAL);
+ sc->ratio2 = r;
+/* BCM_PWM_MEM_WRITE(sc, 0x24, sc->ratio2); */
+ W_DAT(sc, sc->ratio);
return (0);
}
@@ -257,19 +382,31 @@
SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "pwm_freq",
CTLFLAG_RD | CTLTYPE_UINT, sc, 0,
- bcm_pwm_pwm_freq_proc, "IU", "PWM frequency (Hz)");
+ bcm_pwm_pwm_freq_proc, "IU", "PWM frequency ch 1 (Hz)");
SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "period",
CTLFLAG_RW | CTLTYPE_UINT, sc, 0,
- bcm_pwm_period_proc, "IU", "PWM period (#clocks)");
+ bcm_pwm_period_proc, "IU", "PWM period ch 1 (#clocks)");
SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "ratio",
CTLFLAG_RW | CTLTYPE_UINT, sc, 0,
- bcm_pwm_ratio_proc, "IU", "PWM ratio (0...period)");
+ bcm_pwm_ratio_proc, "IU", "PWM ratio ch 1 (0...period)");
SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "freq",
CTLFLAG_RW | CTLTYPE_UINT, sc, 0,
bcm_pwm_freq_proc, "IU", "PWM clock (Hz)");
SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "mode",
CTLFLAG_RW | CTLTYPE_UINT, sc, 0,
- bcm_pwm_mode_proc, "IU", "PWM mode (0=off, 1=pwm, 2=dither)");
+ bcm_pwm_mode_proc, "IU", "PWM mode ch 1 (0=off, 1=pwm, 2=dither)");
+ SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "pwm_freq2",
+ CTLFLAG_RD | CTLTYPE_UINT, sc, 0,
+ bcm_pwm_pwm_freq2_proc, "IU", "PWM frequency ch 2 (Hz)");
+ SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "period2",
+ CTLFLAG_RW | CTLTYPE_UINT, sc, 0,
+ bcm_pwm_period2_proc, "IU", "PWM period ch 2 (#clocks)");
+ SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "ratio2",
+ CTLFLAG_RW | CTLTYPE_UINT, sc, 0,
+ bcm_pwm_ratio2_proc, "IU", "PWM ratio ch 2 (0...period)");
+ SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "mode2",
+ CTLFLAG_RW | CTLTYPE_UINT, sc, 0,
+ bcm_pwm_mode2_proc, "IU", "PWM mode ch 2 (0=off, 1=pwm, 2=dither)");
}
static int
@@ -321,10 +458,11 @@
/* Add sysctl nodes. */
bcm_pwm_sysctl_init(sc);
- sc->freq = 125000000;
- sc->period = 10000;
- sc->ratio = 2500;
-
+ sc->freq = 125000000; /* 125 Mhz */
+ sc->period = 10000; /* 12.5 khz */
+ sc->ratio = 2500; /* 25% */
+ sc->period2 = 10000; /* 12.5 khz */
+ sc->ratio2 = 2500; /* 25% */
return (bus_generic_attach(dev));
}
@@ -338,6 +476,7 @@
sc = device_get_softc(dev);
sc->mode = 0;
+ sc->mode2 = 0;
(void)bcm_pwm_reconf(sc);
if (sc->sc_mem_res)
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Nov 4, 4:18 AM (1 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24732919
Default Alt Text
D15769.id43636.diff (8 KB)
Attached To
Mode
D15769: bcm2835_pwm - add sysctl vars and supporting code for channel 2
Attached
Detach File
Event Timeline
Log In to Comment