summaryrefslogtreecommitdiff
path: root/firmware/target/arm/s3c2440
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/s3c2440')
-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)
32 * Timer input clock frequency = 32 * Timer input clock frequency =
33 * fPCLK / {prescaler value+1} / {divider value} 33 * fPCLK / {prescaler value+1} / {divider value}
34 * TIMER_FREQ = 49156800 / 2 34 * TIMER_FREQ = 49156800 / 2
35 * 13300 = TIMER_FREQ / 231 / 8 35 * 146300 = TIMER_FREQ / 21 / 8
36 * 49156800 = 19*(11)*(7)*7*5*5*(3)*2*2*2*2*2*2 36 * 49156800 = 19*11*(7)*7*5*5*(3)*2*2*2*2*2*2
37 * 231 = 11*7*3 37 * 21 = 7*3
38 */ 38 */
39 39
40 /* stop timer 4 */ 40 /* stop timer 4 */
41 TCON &= ~(1 << 20); 41 TCON &= ~(1 << 20);
42 /* Set the count for timer 4 */ 42 /* Set the count for timer 4 */
43 TCNTB4 = (TIMER_FREQ / 231 / 8) * interval_in_ms / 1000; 43 TCNTB4 = (TIMER_FREQ / TIMER234_PRESCALE / 8) * interval_in_ms / 1000;
44 /* Set the the prescaler value for timers 2,3, and 4 */ 44 /* Set the the prescaler value for timers 2,3, and 4 */
45 TCFG0 = (TCFG0 & ~0xff00) | ((231-1) << 8); 45 TCFG0 = (TCFG0 & ~0xff00) | ((TIMER234_PRESCALE-1) << 8);
46 /* MUX4 = 1/16 */ 46 /* DMA mode off, MUX4 = 1/16 */
47 TCFG1 = (TCFG1 & ~0xff0000) | 0x030000; 47 TCFG1 = (TCFG1 & ~0xff0000) | 0x030000;
48 /* set manual bit */ 48 /* set manual bit */
49 TCON |= 1 << 21; 49 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 @@
23 23
24/* timer is based on PCLK and minimum division is 2 */ 24/* timer is based on PCLK and minimum division is 2 */
25#define TIMER_FREQ (49156800/2) 25#define TIMER_FREQ (49156800/2)
26#define TIMER234_PRESCALE 21
26 27
27bool __timer_set(long cycles, bool set); 28bool __timer_set(long cycles, bool set);
28bool __timer_register(void); 29bool __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 @@
29#include "kernel.h" 29#include "kernel.h"
30#include "sound.h" 30#include "sound.h"
31#include "i2c-meg-fx.h" 31#include "i2c-meg-fx.h"
32#include "system-target.h"
33#include "timer-target.h"
32#include "wmcodec.h" 34#include "wmcodec.h"
33 35
36#ifdef HAVE_HARDWARE_BEEP
37static void beep_stop(void);
38#endif
39
34void audiohw_init(void) 40void audiohw_init(void)
35{ 41{
36 /* GPC5 controls headphone output */ 42 /* GPC5 controls headphone output */
@@ -39,6 +45,14 @@ void audiohw_init(void)
39 GPCDAT |= (1 << 5); 45 GPCDAT |= (1 << 5);
40 46
41 audiohw_preinit(); 47 audiohw_preinit();
48
49#ifdef HAVE_HARDWARE_BEEP
50 /* pin pullup ON */
51 GPBUP &= ~(1 << 3);
52 beep_stop();
53 /* set pin to TIMER3 output (functional TOUT3) */
54 GPBCON = (GPBCON & ~(0x3 << 6)) | (2 << 6);
55#endif
42} 56}
43 57
44void wmcodec_write(int reg, int data) 58void wmcodec_write(int reg, int data)
@@ -48,3 +62,92 @@ void wmcodec_write(int reg, int data)
48 d[1] = data; 62 d[1] = data;
49 i2c_write(0x34, d, 2); 63 i2c_write(0x34, d, 2);
50} 64}
65
66#ifdef HAVE_HARDWARE_BEEP
67/** Beeping via TIMER3 output to codec MONO input **/
68static int beep_cycles = 0;
69static int beep_cycle_count = 0;
70
71static void beep_stop(void)
72{
73 int oldstatus = disable_interrupt_save(IRQ_FIQ_STATUS);
74
75 /* stop interrupt */
76 INTMSK |= TIMER3_MASK;
77 /* stop timer */
78 TCON &= ~(1 << 16);
79 /* be sure timer PWM pin is LOW to avoid noise */
80 TCON ^= (GPBDAT & (1 << 3)) << 15;
81 /* clear pending */
82 SRCPND = TIMER3_MASK;
83 INTPND = TIMER3_MASK;
84
85 restore_interrupt(oldstatus);
86}
87
88/* Timer interrupt called on every cycle */
89void TIMER3(void)
90{
91 if (++beep_cycles >= beep_cycle_count)
92 {
93 /* beep is complete */
94 beep_stop();
95 }
96
97 /* clear pending */
98 SRCPND = TIMER3_MASK;
99 INTPND = TIMER3_MASK;
100}
101
102void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude)
103{
104 #define TIMER3_TICK_SEC (TIMER_FREQ / TIMER234_PRESCALE)
105
106 unsigned long tcnt, tcmp;
107 int oldstatus;
108
109 if (amplitude <= 0)
110 {
111 beep_stop(); /* won't hear it anyway */
112 return;
113 }
114
115 /* pretend this is pcm */
116 if (amplitude > 32767)
117 amplitude = 32767;
118
119 /* limit frequency range to keep math in range */
120 if (frequency > 19506)
121 frequency = 19506;
122 else if (frequency < 18)
123 frequency = 18;
124
125 /* set timer */
126 tcnt = TIMER3_TICK_SEC / frequency;
127
128 oldstatus = disable_interrupt_save(IRQ_FIQ_STATUS);
129
130 beep_cycles = 0;
131 beep_cycle_count = TIMER3_TICK_SEC * duration / (tcnt*1000);
132
133 /* divider = 1/2 */
134 TCFG1 = (TCFG1 & ~(0xf << 12)) | (0 << 12);
135 /* stop TIMER3, inverter OFF */
136 TCON &= ~((1 << 18) | (1 << 16));
137 /* set countdown */
138 TCNTB3 = tcnt;
139 /* set PWM counter - control volume with duty cycle. */
140 tcmp = tcnt*amplitude / (65536*2 - 2*amplitude);
141 TCMPB3 = tcmp < 1 ? 1 : tcmp;
142 /* manual update: on (to reset count), interval mode (auto reload) */
143 TCON |= (1 << 19) | (1 << 17);
144 /* clear manual bit */
145 TCON &= ~(1 << 17);
146 /* start timer */
147 TCON |= (1 << 16);
148 /* enable timer interrupt */
149 INTMSK &= ~TIMER3_MASK;
150
151 restore_interrupt(oldstatus);
152}
153#endif /* HAVE_HARDWARE_BEEP */