--- /dev/null
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/power.h>
+#include <util/delay.h>
+#include <util/atomic.h>
+
+#include "lights.h"
+
+/*
+ * Single PWM channel on OC1B (pin PB4 of Tiny45).
+ * Counts from 0 to 0xFF, without OCR1C compare.
+ */
+
+volatile unsigned char pwm_enabled;
+
+static void inline enable_pll()
+{
+ /* Async clock */
+ PLLCSR = _BV(PLLE) | _BV(LSM);
+
+ /* Synchronize to the phase lock */
+ _delay_us(100);
+ while ((PLLCSR & _BV(PLOCK)) == 0)
+ ;
+ PLLCSR |= _BV(PCKE);
+}
+
+void init_pwm()
+{
+ pwm_enabled = 0;
+ power_timer1_enable();
+
+ TCCR1 = _BV(CTC1) | _BV(CS11); // pll_clk/2
+ GTCCR = _BV(COM1B1) | _BV(PWM1B);
+
+ OCR1C = PWM_MAX;
+ OCR1B = 0; // initial stride is 0
+
+ DDRB &= ~(_BV( PB4 ));
+ PORTB &= ~_BV(PB4); // set to zero
+}
+
+void susp_pwm()
+{
+ DDRB &= ~(_BV( PB4 ));
+ PORTB &= ~(_BV( PB4 ));
+ TCCR1 = 0;
+ TIMSK = 0;
+ TIFR = 0;
+
+ PLLCSR &= ~(_BV(PLLE) | _BV(PCKE));
+}
+
+void pwm_off()
+{
+ OCR1B = 0;
+ DDRB &= ~_BV(PB4);
+
+ PLLCSR &= ~(_BV(PLLE) | _BV(PCKE));
+ power_timer1_disable();
+ pwm_enabled = 0;
+}
+
+void pwm_set(uint8_t stride)
+{
+ OCR1B = stride;
+
+ if (!pwm_enabled) {
+ power_timer1_enable();
+ enable_pll();
+ DDRB |= _BV(PB4);
+ pwm_enabled = 1;
+ }
+}