summaryrefslogtreecommitdiffstats
path: root/firmware/target/arm/s3c2440/gigabeat-fx
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2008-12-07 00:07:47 +0000
committerMichael Sevakis <jethead71@rockbox.org>2008-12-07 00:07:47 +0000
commit89da4328a07c8736c42843607a3f3bf91c17601d (patch)
treecbd5d6580b2c62dad5830c043d9284ff15cf7bdf /firmware/target/arm/s3c2440/gigabeat-fx
parent3648e8705402ce5a0af2125987f12c884b540eea (diff)
downloadrockbox-89da4328a07c8736c42843607a3f3bf91c17601d.tar.gz
rockbox-89da4328a07c8736c42843607a3f3bf91c17601d.zip
Meg F/X can beep and click using a hardware timer so let us try it out. To match things up better, fix PCM beeping to give correct frequency (and get a pointer wrap bug too). Do some minor adjustments to compensate for corrections.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19355 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/s3c2440/gigabeat-fx')
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c12
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/timer-target.h1
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c103
3 files changed, 110 insertions, 6 deletions
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c
index 76917c8c82..5ef8c8023a 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c
@@ -32,18 +32,18 @@ void tick_start(unsigned int interval_in_ms)
* Timer input clock frequency =
* fPCLK / {prescaler value+1} / {divider value}
* TIMER_FREQ = 49156800 / 2
- * 13300 = TIMER_FREQ / 231 / 8
- * 49156800 = 19*(11)*(7)*7*5*5*(3)*2*2*2*2*2*2
- * 231 = 11*7*3
+ * 146300 = TIMER_FREQ / 21 / 8
+ * 49156800 = 19*11*(7)*7*5*5*(3)*2*2*2*2*2*2
+ * 21 = 7*3
*/
/* stop timer 4 */
TCON &= ~(1 << 20);
/* Set the count for timer 4 */
- TCNTB4 = (TIMER_FREQ / 231 / 8) * interval_in_ms / 1000;
+ TCNTB4 = (TIMER_FREQ / TIMER234_PRESCALE / 8) * interval_in_ms / 1000;
/* Set the the prescaler value for timers 2,3, and 4 */
- TCFG0 = (TCFG0 & ~0xff00) | ((231-1) << 8);
- /* MUX4 = 1/16 */
+ TCFG0 = (TCFG0 & ~0xff00) | ((TIMER234_PRESCALE-1) << 8);
+ /* DMA mode off, MUX4 = 1/16 */
TCFG1 = (TCFG1 & ~0xff0000) | 0x030000;
/* set manual bit */
TCON |= 1 << 21;
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/timer-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/timer-target.h
index ac195bf9a5..b5652a3365 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/timer-target.h
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/timer-target.h
@@ -23,6 +23,7 @@
/* timer is based on PCLK and minimum division is 2 */
#define TIMER_FREQ (49156800/2)
+#define TIMER234_PRESCALE 21
bool __timer_set(long cycles, bool set);
bool __timer_register(void);
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c
index 957d58b344..de965f0750 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c
@@ -29,8 +29,14 @@
#include "kernel.h"
#include "sound.h"
#include "i2c-meg-fx.h"
+#include "system-target.h"
+#include "timer-target.h"
#include "wmcodec.h"
+#ifdef HAVE_HARDWARE_BEEP
+static void beep_stop(void);
+#endif
+
void audiohw_init(void)
{
/* GPC5 controls headphone output */
@@ -39,6 +45,14 @@ void audiohw_init(void)
GPCDAT |= (1 << 5);
audiohw_preinit();
+
+#ifdef HAVE_HARDWARE_BEEP
+ /* pin pullup ON */
+ GPBUP &= ~(1 << 3);
+ beep_stop();
+ /* set pin to TIMER3 output (functional TOUT3) */
+ GPBCON = (GPBCON & ~(0x3 << 6)) | (2 << 6);
+#endif
}
void wmcodec_write(int reg, int data)
@@ -48,3 +62,92 @@ void wmcodec_write(int reg, int data)
d[1] = data;
i2c_write(0x34, d, 2);
}
+
+#ifdef HAVE_HARDWARE_BEEP
+/** Beeping via TIMER3 output to codec MONO input **/
+static int beep_cycles = 0;
+static int beep_cycle_count = 0;
+
+static void beep_stop(void)
+{
+ int oldstatus = disable_interrupt_save(IRQ_FIQ_STATUS);
+
+ /* stop interrupt */
+ INTMSK |= TIMER3_MASK;
+ /* stop timer */
+ TCON &= ~(1 << 16);
+ /* be sure timer PWM pin is LOW to avoid noise */
+ TCON ^= (GPBDAT & (1 << 3)) << 15;
+ /* clear pending */
+ SRCPND = TIMER3_MASK;
+ INTPND = TIMER3_MASK;
+
+ restore_interrupt(oldstatus);
+}
+
+/* Timer interrupt called on every cycle */
+void TIMER3(void)
+{
+ if (++beep_cycles >= beep_cycle_count)
+ {
+ /* beep is complete */
+ beep_stop();
+ }
+
+ /* clear pending */
+ SRCPND = TIMER3_MASK;
+ INTPND = TIMER3_MASK;
+}
+
+void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude)
+{
+ #define TIMER3_TICK_SEC (TIMER_FREQ / TIMER234_PRESCALE)
+
+ unsigned long tcnt, tcmp;
+ int oldstatus;
+
+ if (amplitude <= 0)
+ {
+ beep_stop(); /* won't hear it anyway */
+ return;
+ }
+
+ /* pretend this is pcm */
+ if (amplitude > 32767)
+ amplitude = 32767;
+
+ /* limit frequency range to keep math in range */
+ if (frequency > 19506)
+ frequency = 19506;
+ else if (frequency < 18)
+ frequency = 18;
+
+ /* set timer */
+ tcnt = TIMER3_TICK_SEC / frequency;
+
+ oldstatus = disable_interrupt_save(IRQ_FIQ_STATUS);
+
+ beep_cycles = 0;
+ beep_cycle_count = TIMER3_TICK_SEC * duration / (tcnt*1000);
+
+ /* divider = 1/2 */
+ TCFG1 = (TCFG1 & ~(0xf << 12)) | (0 << 12);
+ /* stop TIMER3, inverter OFF */
+ TCON &= ~((1 << 18) | (1 << 16));
+ /* set countdown */
+ TCNTB3 = tcnt;
+ /* set PWM counter - control volume with duty cycle. */
+ tcmp = tcnt*amplitude / (65536*2 - 2*amplitude);
+ TCMPB3 = tcmp < 1 ? 1 : tcmp;
+ /* manual update: on (to reset count), interval mode (auto reload) */
+ TCON |= (1 << 19) | (1 << 17);
+ /* clear manual bit */
+ TCON &= ~(1 << 17);
+ /* start timer */
+ TCON |= (1 << 16);
+ /* enable timer interrupt */
+ INTMSK &= ~TIMER3_MASK;
+
+ restore_interrupt(oldstatus);
+}
+#endif /* HAVE_HARDWARE_BEEP */