summaryrefslogtreecommitdiff
path: root/firmware/target/arm
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm')
-rw-r--r--firmware/target/arm/imx31/debug-imx31.c121
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c228
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/system-imx31.c10
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/system-target.h5
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c36
5 files changed, 369 insertions, 31 deletions
diff --git a/firmware/target/arm/imx31/debug-imx31.c b/firmware/target/arm/imx31/debug-imx31.c
index 94df64b6d7..9fe2eae584 100644
--- a/firmware/target/arm/imx31/debug-imx31.c
+++ b/firmware/target/arm/imx31/debug-imx31.c
@@ -27,9 +27,128 @@
27#include "mc13783.h" 27#include "mc13783.h"
28#include "adc.h" 28#include "adc.h"
29 29
30#define CONFIG_CLK32_FREQ 32768
31#define CONFIG_HCLK_FREQ 27000000
32
33/* Return PLL frequency in HZ */
34static unsigned int decode_pll(unsigned int reg,
35 unsigned int infreq)
36{
37 uint64_t mfi = (reg >> 10) & 0xf;
38 uint64_t mfn = reg & 0x3ff;
39 uint64_t mfd = ((reg >> 16) & 0x3ff) + 1;
40 uint64_t pd = ((reg >> 26) & 0xf) + 1;
41
42 mfi = mfi <= 5 ? 5 : mfi;
43
44 return 2*infreq*(mfi * mfd + mfn) / (mfd * pd);
45}
46
47/* Get the PLL reference clock frequency */
48static unsigned int get_pll_ref_clk_freq(void)
49{
50 if ((CLKCTL_CCMR & (3 << 1)) == (1 << 1))
51 return CONFIG_CLK32_FREQ * 1024;
52 else
53 return CONFIG_HCLK_FREQ;
54}
55
30bool __dbg_hw_info(void) 56bool __dbg_hw_info(void)
31{ 57{
32 return false; 58 char buf[50];
59 int line;
60 unsigned int pllref;
61 unsigned int mcu_pllfreq, ser_pllfreq, usb_pllfreq;
62 uint32_t mpctl, spctl, upctl;
63 unsigned int freq;
64 uint32_t regval;
65
66 lcd_setmargins(0, 0);
67 lcd_clear_display();
68 lcd_setfont(FONT_SYSFIXED);
69
70 while (1)
71 {
72 line = 0;
73 mpctl = CLKCTL_MPCTL;
74 spctl = CLKCTL_SPCTL;
75 upctl = CLKCTL_UPCTL;
76
77 pllref = get_pll_ref_clk_freq();
78
79 mcu_pllfreq = decode_pll(mpctl, pllref);
80 ser_pllfreq = decode_pll(spctl, pllref);
81 usb_pllfreq = decode_pll(upctl, pllref);
82
83 snprintf(buf, sizeof (buf), "pll_ref_clk: %u", pllref);
84 lcd_puts(0, line++, buf); line++;
85
86 /* MCU clock domain */
87 snprintf(buf, sizeof (buf), "MPCTL: %08lX", mpctl);
88 lcd_puts(0, line++, buf);
89
90 snprintf(buf, sizeof (buf), " mpl_dpdgck_clk: %u", mcu_pllfreq);
91 lcd_puts(0, line++, buf); line++;
92
93 regval = CLKCTL_PDR0;
94 snprintf(buf, sizeof (buf), " PDR0: %08lX", regval);
95 lcd_puts(0, line++, buf);
96
97 freq = mcu_pllfreq / (((regval & 0x7) + 1));
98 snprintf(buf, sizeof (buf), " mcu_clk: %u", freq);
99 lcd_puts(0, line++, buf);
100
101 freq = mcu_pllfreq / (((regval >> 11) & 0x7) + 1);
102 snprintf(buf, sizeof (buf), " hsp_clk: %u", freq);
103 lcd_puts(0, line++, buf);
104
105 freq = mcu_pllfreq / (((regval >> 3) & 0x7) + 1);
106 snprintf(buf, sizeof (buf), " hclk_clk: %u", freq);
107 lcd_puts(0, line++, buf);
108
109 snprintf(buf, sizeof (buf), " ipg_clk: %u",
110 freq / (unsigned)(((regval >> 6) & 0x3) + 1));
111 lcd_puts(0, line++, buf);
112
113 snprintf(buf, sizeof (buf), " nfc_clk: %u",
114 freq / (unsigned)(((regval >> 8) & 0x7) + 1));
115 lcd_puts(0, line++, buf);
116
117 line++;
118
119 /* Serial clock domain */
120 snprintf(buf, sizeof (buf), "SPCTL: %08lX", spctl);
121 lcd_puts(0, line++, buf);
122 snprintf(buf, sizeof (buf), " spl_dpdgck_clk: %u", ser_pllfreq);
123 lcd_puts(0, line++, buf);
124
125 line++;
126
127 /* USB clock domain */
128 snprintf(buf, sizeof (buf), "UPCTL: %08lX", upctl);
129 lcd_puts(0, line++, buf);
130
131 snprintf(buf, sizeof (buf), " upl_dpdgck_clk: %u", usb_pllfreq);
132 lcd_puts(0, line++, buf); line++;
133
134 regval = CLKCTL_PDR1;
135 snprintf(buf, sizeof (buf), " PDR1: %08lX", regval);
136 lcd_puts(0, line++, buf);
137
138 freq = usb_pllfreq /
139 ((((regval >> 30) & 0x3) + 1) * (((regval >> 27) & 0x7) + 1));
140 snprintf(buf, sizeof (buf), " usb_clk: %u", freq);
141 lcd_puts(0, line++, buf);
142
143 freq = usb_pllfreq / (((CLKCTL_PDR0 >> 16) & 0x1f) + 1);
144 snprintf(buf, sizeof (buf), " ipg_per_baud: %u", freq);
145 lcd_puts(0, line++, buf);
146
147 lcd_update();
148
149 if (button_get(true) == (DEBUG_CANCEL|BUTTON_REL))
150 return false;
151 }
33} 152}
34 153
35bool __dbg_ports(void) 154bool __dbg_ports(void)
diff --git a/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c b/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c
index e37f6bfbe2..9ac96fd801 100644
--- a/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c
@@ -7,7 +7,7 @@
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2006 by Michael Sevakis 10 * Copyright (C) 2008 by Michael Sevakis
11 * 11 *
12 * All files in this archive are subject to the GNU General Public License. 12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement. 13 * See the file COPYING in the source tree root for full license agreement.
@@ -19,69 +19,256 @@
19#include <stdlib.h> 19#include <stdlib.h>
20#include "system.h" 20#include "system.h"
21#include "kernel.h" 21#include "kernel.h"
22#include "logf.h"
23#include "audio.h" 22#include "audio.h"
24#include "sound.h" 23#include "sound.h"
25#include "file.h" 24#include "avic-imx31.h"
26#include "mmu-imx31.h" 25#include "clkctl-imx31.h"
27 26
28#if 0 27/* This isn't DMA-based at the moment and is handled like Portal Player but
29static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */ 28 * will suffice for starters. */
30#endif 29
30struct dma_data
31{
32 uint16_t *p;
33 size_t size;
34 int locked;
35 int state;
36};
37
38static unsigned long pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */
39
40static struct dma_data dma_play_data =
41{
42 /* Initialize to a locked, stopped state */
43 .p = NULL,
44 .size = 0,
45 .locked = 0,
46 .state = 0
47};
31 48
32void pcm_play_lock(void) 49void pcm_play_lock(void)
33{ 50{
51 if (++dma_play_data.locked == 1)
52 {
53 /* Atomically disable transmit interrupt */
54 imx31_regmod32(&SSI_SIER1, 0, SSI_SIER_TIE);
55 }
34} 56}
35 57
36void pcm_play_unlock(void) 58void pcm_play_unlock(void)
37{ 59{
60 if (--dma_play_data.locked == 0 && dma_play_data.state != 0)
61 {
62 /* Atomically enable transmit interrupt */
63 imx31_regmod32(&SSI_SIER1, SSI_SIER_TIE, SSI_SIER_TIE);
64 }
38} 65}
39 66
40#if 0
41static void _pcm_apply_settings(void) 67static void _pcm_apply_settings(void)
42{ 68{
69 if (pcm_freq != pcm_curr_sampr)
70 {
71 pcm_curr_sampr = pcm_freq;
72 // TODO: audiohw_set_frequency(sr_ctrl);
73 }
74}
75
76static void __attribute__((interrupt("IRQ"))) SSI1_HANDLER(void)
77{
78 register pcm_more_callback_type get_more;
79
80 do
81 {
82 while (dma_play_data.size > 0)
83 {
84 if (SSI_SFCSR_TFCNT0r(SSI_SFCSR1) > 6)
85 {
86 return;
87 }
88 SSI_STX0_1 = *dma_play_data.p++;
89 SSI_STX0_1 = *dma_play_data.p++;
90 dma_play_data.size -= 4;
91 }
92
93 /* p is empty, get some more data */
94 get_more = pcm_callback_for_more;
95
96 if (get_more)
97 {
98 get_more((unsigned char **)&dma_play_data.p,
99 &dma_play_data.size);
100 }
101 }
102 while (dma_play_data.size > 0);
103
104 /* No more data, so disable the FIFO/interrupt */
105 pcm_play_dma_stop();
106 pcm_play_dma_stopped_callback();
43} 107}
44#endif
45 108
46void pcm_apply_settings(void) 109void pcm_apply_settings(void)
47{ 110{
111 int oldstatus = disable_fiq_save();
112
113 _pcm_apply_settings();
114
115 restore_fiq(oldstatus);
48} 116}
49 117
50void pcm_play_dma_init(void) 118void pcm_play_dma_init(void)
51{ 119{
120 imx31_clkctl_module_clock_gating(CG_SSI1, CGM_ON_ALL);
121 imx31_clkctl_module_clock_gating(CG_SSI2, CGM_ON_ALL);
122
123 /* Reset & disable SSIs */
124 SSI_SCR2 &= ~SSI_SCR_SSIEN;
125 SSI_SCR1 &= ~SSI_SCR_SSIEN;
126
127 SSI_SIER1 = SSI_SIER_TFE0;
128 SSI_SIER2 = 0;
129
130 /* Set up audio mux */
131
132 /* Port 1 (internally connected to SSI1)
133 * All clocking is output sourced from port 4 */
134 AUDMUX_PTCR1 = AUDMUX_PTCR_TFS_DIR | AUDMUX_PTCR_TFSEL_PORT4 |
135 AUDMUX_PTCR_TCLKDIR | AUDMUX_PTCR_TCSEL_PORT4 |
136 AUDMUX_PTCR_RFSDIR | AUDMUX_PTCR_RFSSEL_PORT4 |
137 AUDMUX_PTCR_RCLKDIR | AUDMUX_PTCR_RCSEL_PORT4 |
138 AUDMUX_PTCR_SYN;
139
140 /* Receive data from port 4 */
141 AUDMUX_PDCR1 = AUDMUX_PDCR_RXDSEL_PORT4;
142 /* All clock lines are inputs sourced from the master mode codec and
143 * sent back to SSI1 through port 1 */
144 AUDMUX_PTCR4 = AUDMUX_PTCR_SYN;
145
146 /* Receive data from port 1 */
147 AUDMUX_PDCR4 = AUDMUX_PDCR_RXDSEL_PORT1;
148
149 /* Port 2 (internally connected to SSI2) routes clocking to port 5 to
150 * provide MCLK to the codec */
151 /* All port 2 clocks are inputs taken from SSI2 */
152 AUDMUX_PTCR2 = 0;
153 AUDMUX_PDCR2 = 0;
154 /* Port 5 outputs TCLK sourced from port 2 */
155 AUDMUX_PTCR5 = AUDMUX_PTCR_TCLKDIR | AUDMUX_PTCR_TCSEL_PORT2;
156 AUDMUX_PDCR5 = 0;
157
158 /* Setup SSIs */
159
160 /* SSI1 - interface for all I2S data */
161 SSI_SCR1 = SSI_SCR_SYN | SSI_SCR_I2S_MODE_SLAVE;
162 SSI_STCR1 = SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSI |
163 SSI_STCR_TEFS | SSI_STCR_TFEN0;
164
165 /* 16 bits per word, 2 words per frame */
166 SSI_STCCR1 = SSI_STRCCR_WL16 | SSI_STRCCR_DCw(2-1) |
167 SSI_STRCCR_PMw(4-1);
168
169 SSI_STMSK1 = 0;
170
171 /* Receive */
172 SSI_SRCR1 = SSI_SRCR_RXBIT0 | SSI_SRCR_RSCKP | SSI_SRCR_RFSI |
173 SSI_SRCR_REFS | SSI_SRCR_RFEN0;
174
175 /* 16 bits per word, 2 words per frame */
176 SSI_SRCCR1 = SSI_STRCCR_WL16 | SSI_STRCCR_DCw(2-1) |
177 SSI_STRCCR_PMw(4-1);
178
179 /* Receive high watermark - 6 samples in FIFO
180 * Transmit low watermark - 2 samples in FIFO */
181 SSI_SFCSR1 = SSI_SFCSR_RFWM1w(8) | SSI_SFCSR_TFWM1w(1) |
182 SSI_SFCSR_RFWM0w(6) | SSI_SFCSR_TFWM0w(2);
183
184 SSI_SRMSK1 = 0;
185
186 /* SSI2 - provides MCLK only */
187 SSI_SCR2 = 0;
188 SSI_SRCR2 = 0;
189 SSI_STCR2 = SSI_STCR_TXDIR;
190 SSI_STCCR2 = SSI_STRCCR_PMw(0);
191
192 /* Enable SSIs */
193 SSI_SCR2 |= SSI_SCR_SSIEN;
194
52 audiohw_init(); 195 audiohw_init();
53} 196}
54 197
55void pcm_postinit(void) 198void pcm_postinit(void)
56{ 199{
57 audiohw_postinit(); 200 audiohw_postinit();
201 avic_enable_int(SSI1, IRQ, 8, SSI1_HANDLER);
58} 202}
59 203
60#if 0
61/* Connect the DMA and start filling the FIFO */
62static void play_start_pcm(void) 204static void play_start_pcm(void)
63{ 205{
206 /* Stop transmission (if in progress) */
207 SSI_SCR1 &= ~SSI_SCR_TE;
208
209 /* Apply new settings */
210 _pcm_apply_settings();
211
212 /* Enable interrupt on unlock */
213 dma_play_data.state = 1;
214
215 /* Fill the FIFO or start when data is used up */
216 while (1)
217 {
218 if (SSI_SFCSR_TFCNT0r(SSI_SFCSR1) > 6 || dma_play_data.size == 0)
219 {
220 SSI_SCR1 |= (SSI_SCR_TE | SSI_SCR_SSIEN); /* Start transmitting */
221 return;
222 }
223
224 SSI_STX0_1 = *dma_play_data.p++;
225 SSI_STX0_1 = *dma_play_data.p++;
226 dma_play_data.size -= 4;
227 }
64} 228}
65 229
66/* Disconnect the DMA and wait for the FIFO to clear */
67static void play_stop_pcm(void) 230static void play_stop_pcm(void)
68{ 231{
232 /* Disable interrupt */
233 SSI_SIER1 &= ~SSI_SIER_TIE;
234
235 /* Wait for FIFO to empty */
236 while (SSI_SFCSR_TFCNT0r(SSI_SFCSR1) > 0);
237
238 /* Disable transmission */
239 SSI_SCR1 &= ~(SSI_SCR_TE | SSI_SCR_SSIEN);
240
241 /* Do not enable interrupt on unlock */
242 dma_play_data.state = 0;
69} 243}
70#endif
71 244
72void pcm_play_dma_start(const void *addr, size_t size) 245void pcm_play_dma_start(const void *addr, size_t size)
73{ 246{
74 (void)addr; 247 dma_play_data.p = (void *)(((uintptr_t)addr + 3) & ~3);
75 (void)size; 248 dma_play_data.size = (size & ~3);
249
250 play_start_pcm();
76} 251}
77 252
78void pcm_play_dma_stop(void) 253void pcm_play_dma_stop(void)
79{ 254{
255 play_stop_pcm();
256 dma_play_data.size = 0;
80} 257}
81 258
82void pcm_play_dma_pause(bool pause) 259void pcm_play_dma_pause(bool pause)
83{ 260{
84 (void)pause; 261 if (pause)
262 {
263 play_stop_pcm();
264 }
265 else
266 {
267 uint32_t addr = (uint32_t)dma_play_data.p;
268 dma_play_data.p = (void *)((addr + 2) & ~3);
269 dma_play_data.size &= ~3;
270 play_start_pcm();
271 }
85} 272}
86 273
87/* Set the pcm frequency hardware will use when play is next started or 274/* Set the pcm frequency hardware will use when play is next started or
@@ -89,20 +276,23 @@ void pcm_play_dma_pause(bool pause)
89 hardware here but simply cache it. */ 276 hardware here but simply cache it. */
90void pcm_set_frequency(unsigned int frequency) 277void pcm_set_frequency(unsigned int frequency)
91{ 278{
279 /* TODO */
92 (void)frequency; 280 (void)frequency;
93} 281}
94 282
95/* Return the number of bytes waiting - full L-R sample pairs only */ 283/* Return the number of bytes waiting - full L-R sample pairs only */
96size_t pcm_get_bytes_waiting(void) 284size_t pcm_get_bytes_waiting(void)
97{ 285{
98 return 0; 286 return dma_play_data.size & ~3;
99} 287}
100 288
101/* Return a pointer to the samples and the number of them in *count */ 289/* Return a pointer to the samples and the number of them in *count */
102const void * pcm_play_dma_get_peak_buffer(int *count) 290const void * pcm_play_dma_get_peak_buffer(int *count)
103{ 291{
104 (void)count; 292 uint32_t addr = (uint32_t)dma_play_data.p;
105 return NULL; 293 size_t cnt = dma_play_data.size;
294 *count = cnt >> 2;
295 return (void *)((addr + 2) & ~3);
106} 296}
107 297
108/* Any recording functionality should be implemented similarly */ 298/* Any recording functionality should be implemented similarly */
diff --git a/firmware/target/arm/imx31/gigabeat-s/system-imx31.c b/firmware/target/arm/imx31/gigabeat-s/system-imx31.c
index da5026a292..ca82a18fbd 100644
--- a/firmware/target/arm/imx31/gigabeat-s/system-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/system-imx31.c
@@ -27,6 +27,16 @@ void system_init(void)
27 gpio_init(); 27 gpio_init();
28} 28}
29 29
30void imx31_regmod32(volatile uint32_t *reg_p, uint32_t mask, uint32_t value)
31{
32 value &= mask;
33 mask = ~mask;
34
35 int oldlevel = disable_interrupt_save(IRQ_FIQ_STATUS);
36 *reg_p = (*reg_p & mask) | value;
37 restore_interrupt(oldlevel);
38}
39
30#ifdef BOOTLOADER 40#ifdef BOOTLOADER
31void system_prepare_fw_start(void) 41void system_prepare_fw_start(void)
32{ 42{
diff --git a/firmware/target/arm/imx31/gigabeat-s/system-target.h b/firmware/target/arm/imx31/gigabeat-s/system-target.h
index 241f215dc1..766de7328f 100644
--- a/firmware/target/arm/imx31/gigabeat-s/system-target.h
+++ b/firmware/target/arm/imx31/gigabeat-s/system-target.h
@@ -24,16 +24,21 @@
24 24
25#define CPUFREQ_NORMAL 532000000 25#define CPUFREQ_NORMAL 532000000
26 26
27#if 0
27static inline void udelay(unsigned int usecs) 28static inline void udelay(unsigned int usecs)
28{ 29{
29 volatile signed int stop = EPITCNT1 - usecs; 30 volatile signed int stop = EPITCNT1 - usecs;
30 while ((signed int)EPITCNT1 > stop); 31 while ((signed int)EPITCNT1 > stop);
31} 32}
33#endif
32 34
33void system_prepare_fw_start(void); 35void system_prepare_fw_start(void);
34void tick_stop(void); 36void tick_stop(void);
35void kernel_device_init(void); 37void kernel_device_init(void);
36 38
39void imx31_regmod32(volatile uint32_t *reg_p, uint32_t value,
40 uint32_t mask);
41
37#define KDEV_INIT 42#define KDEV_INIT
38 43
39#define HAVE_INVALIDATE_ICACHE 44#define HAVE_INVALIDATE_ICACHE
diff --git a/firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c b/firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c
index 235ae54bad..c8a04ce20e 100644
--- a/firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c
@@ -7,14 +7,9 @@
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Gigabeat S specific code for the WM8978 codec 10 * Gigabeat S specific code for the WM8978 codec
11 * 11 *
12 * Based on code from the ipodlinux project - http://ipodlinux.org/ 12 * Copyright (C) 2008 Michael Sevakis
13 * Adapted for Rockbox in December 2005
14 *
15 * Original file: linux/arch/armnommu/mach-ipod/audio.c
16 *
17 * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org)
18 * 13 *
19 * All files in this archive are subject to the GNU General Public License. 14 * All files in this archive are subject to the GNU General Public License.
20 * See the file COPYING in the source tree root for full license agreement. 15 * See the file COPYING in the source tree root for full license agreement.
@@ -23,7 +18,8 @@
23 * KIND, either express or implied. 18 * KIND, either express or implied.
24 * 19 *
25 ****************************************************************************/ 20 ****************************************************************************/
26#include "cpu.h" 21#include "config.h"
22#include "system.h"
27#include "kernel.h" 23#include "kernel.h"
28#include "sound.h" 24#include "sound.h"
29#include "i2c-imx31.h" 25#include "i2c-imx31.h"
@@ -37,15 +33,33 @@ static struct i2c_node wm8978_i2c_node =
37 .ifdr = I2C_IFDR_DIV192, /* 66MHz/.4MHz = 165, closest = 192 = 343750Hz */ 33 .ifdr = I2C_IFDR_DIV192, /* 66MHz/.4MHz = 165, closest = 192 = 343750Hz */
38 /* Just hard-code for now - scaling may require 34 /* Just hard-code for now - scaling may require
39 * updating */ 35 * updating */
40 .addr = WM8978_I2C_ADDR, 36 .addr = WMC_I2C_ADDR,
41}; 37};
42 38
43void audiohw_init(void) 39void audiohw_init(void)
44{ 40{
41 /* USB PLL = 338.688MHz, /30 = 11.2896MHz = 256Fs */
42 imx31_regmod32(&CLKCTL_PDR1, PDR1_SSI1_PODF | PDR1_SSI2_PODF,
43 PDR1_SSI1_PODFw(64-1) | PDR1_SSI2_PODFw(5-1));
44 imx31_regmod32(&CLKCTL_PDR1, PDR1_SSI1_PRE_PODF | PDR1_SSI2_PRE_PODF,
45 PDR1_SSI1_PRE_PODFw(4-1) | PDR1_SSI2_PRE_PODFw(1-1));
45 i2c_enable_node(&wm8978_i2c_node, true); 46 i2c_enable_node(&wm8978_i2c_node, true);
46 GPIO3_DR |= (1 << 21); /* Turn on analogue LDO */ 47
47 sleep(HZ/10); /* Wait for things to stabilize */
48 audiohw_preinit(); 48 audiohw_preinit();
49
50 GPIO3_DR |= (1 << 21); /* Turn on analogue LDO */
51}
52
53void audiohw_enable_headphone_jack(bool enable)
54{
55 if (enable)
56 {
57 GPIO3_DR |= (1 << 22); /* Turn on headphone jack output */
58 }
59 else
60 {
61 GPIO3_DR &= ~(1 << 22); /* Turn off headphone jack output */
62 }
49} 63}
50 64
51void wmcodec_write(int reg, int data) 65void wmcodec_write(int reg, int data)