summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2008-04-27 10:30:54 +0000
committerMichael Sevakis <jethead71@rockbox.org>2008-04-27 10:30:54 +0000
commit27fac88548366f57c32931ed4d7c7dfc5b4f1627 (patch)
treee45132b551ce39a44a6fefa31e85971cea6df47e
parentfec6af659f809d47f6e750975289e220908396fe (diff)
downloadrockbox-27fac88548366f57c32931ed4d7c7dfc5b4f1627.tar.gz
rockbox-27fac88548366f57c32931ed4d7c7dfc5b4f1627.zip
Gigabeat S: Implement i2c driver - transmit works but no testing of receiving which will get a chance later. Add some seeds for codec driver. Correct a few #defines.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17254 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/SOURCES4
-rw-r--r--firmware/drivers/audio/wm8978.c60
-rw-r--r--firmware/export/audiohw.h13
-rw-r--r--firmware/export/config-gigabeat-s.h6
-rwxr-xr-xfirmware/export/imx31l.h108
-rw-r--r--firmware/export/wm8978.h17
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/i2c-imx31.c313
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/i2c-imx31.h56
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c2
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c25
10 files changed, 571 insertions, 33 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 879800ec96..5083357732 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -210,7 +210,9 @@ drivers/mas.c
210drivers/audio/uda1380.c 210drivers/audio/uda1380.c
211#elif defined(HAVE_WM8751) 211#elif defined(HAVE_WM8751)
212drivers/audio/wm8751.c 212drivers/audio/wm8751.c
213#elif defined(HAVE_WM8975) || defined(HAVE_WM8978) 213#elif defined(HAVE_WM8978)
214drivers/audio/wm8978.c
215#elif defined(HAVE_WM8975)
214drivers/audio/wm8975.c 216drivers/audio/wm8975.c
215#elif defined(HAVE_WM8985) 217#elif defined(HAVE_WM8985)
216drivers/audio/wm8985.c 218drivers/audio/wm8985.c
diff --git a/firmware/drivers/audio/wm8978.c b/firmware/drivers/audio/wm8978.c
new file mode 100644
index 0000000000..01f3d331bb
--- /dev/null
+++ b/firmware/drivers/audio/wm8978.c
@@ -0,0 +1,60 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2008 by Michael Sevakis
11 *
12 * Driver for WM8978 audio codec
13 *
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "config.h"
22#include "system.h"
23#include "audiohw.h"
24#include "wmcodec.h"
25#include "audio.h"
26
27const struct sound_settings_info audiohw_settings[] = {
28 [SOUND_VOLUME] = {"dB", 0, 1, -58, 6, -25},
29 [SOUND_BASS] = {"dB", 0, 1, -12, 12, 0},
30 [SOUND_TREBLE] = {"dB", 0, 1, -12, 12, 0},
31 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
32 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
33 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
34 [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0},
35 [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0},
36 [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16},
37#if 0
38 [SOUND_BASS_CUTOFF] = {"", 0, 1, 1, 4, 1},
39 [SOUND_TREBLE_CUTOFF] = {"", 0, 1, 1, 4, 1},
40#endif
41};
42
43void audiohw_preinit(void)
44{
45 wmcodec_write(WM8978_SOFTWARE_RESET, 0);
46}
47
48void audiohw_postinit(void)
49{
50 sleep(HZ);
51}
52
53void audiohw_close(void)
54{
55}
56
57void audiohw_mute(bool mute)
58{
59 (void)mute;
60}
diff --git a/firmware/export/audiohw.h b/firmware/export/audiohw.h
index 73c50b8412..190fcca7a8 100644
--- a/firmware/export/audiohw.h
+++ b/firmware/export/audiohw.h
@@ -27,7 +27,9 @@
27#include "uda1380.h" 27#include "uda1380.h"
28#elif defined(HAVE_WM8751) 28#elif defined(HAVE_WM8751)
29#include "wm8751.h" 29#include "wm8751.h"
30#elif defined(HAVE_WM8975) || defined(HAVE_WM8978) 30#elif defined(HAVE_WM8978)
31#include "wm8978.h"
32#elif defined(HAVE_WM8975)
31#include "wm8975.h" 33#include "wm8975.h"
32#elif defined(HAVE_WM8985) 34#elif defined(HAVE_WM8985)
33#include "wm8985.h" 35#include "wm8985.h"
@@ -109,7 +111,14 @@ extern const struct sound_settings_info audiohw_settings[];
109void audiohw_init(void); 111void audiohw_init(void);
110 112
111/** 113/**
112 * Do some stuff (codec related) after audiohw_init. 114 * Do initial audio codec setup.
115 */
116void audiohw_preinit(void);
117
118/**
119 * Do some stuff (codec related) after audiohw_init that needs to be
120 * delayed such as enabling outputs to prevent popping. This lets
121 * other inits in the system complete in the meantime.
113 */ 122 */
114void audiohw_postinit(void); 123void audiohw_postinit(void);
115 124
diff --git a/firmware/export/config-gigabeat-s.h b/firmware/export/config-gigabeat-s.h
index 6eb57b219c..3e36e0c7ea 100644
--- a/firmware/export/config-gigabeat-s.h
+++ b/firmware/export/config-gigabeat-s.h
@@ -66,10 +66,9 @@
66/* The number of bytes reserved for loadable plugins */ 66/* The number of bytes reserved for loadable plugins */
67#define PLUGIN_BUFFER_SIZE 0x80000 67#define PLUGIN_BUFFER_SIZE 0x80000
68 68
69/* Define this if you have the WM8975 audio codec */ 69/* Define this if you have the WM8978 audio codec */
70#define HAVE_WM8978 70#define HAVE_WM8978
71 71
72
73#define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | \ 72#define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | \
74 SAMPR_CAP_11) 73 SAMPR_CAP_11)
75 74
@@ -85,8 +84,9 @@
85/* Define this if you want to use coldfire's i2c interface */ 84/* Define this if you want to use coldfire's i2c interface */
86#define CONFIG_I2C I2C_IMX31L 85#define CONFIG_I2C I2C_IMX31L
87 86
88/* Define the bitmask of serial interface modules (CSPI) used */ 87/* Define the bitmask of modules used */
89#define SPI_MODULE_MASK (USE_CSPI2_MODULE) 88#define SPI_MODULE_MASK (USE_CSPI2_MODULE)
89#define I2C_MODULE_MASK (USE_I2C1_MODULE)
90 90
91/* Define this if target has an additional number of threads specific to it */ 91/* Define this if target has an additional number of threads specific to it */
92#define TARGET_EXTRA_THREADS 1 92#define TARGET_EXTRA_THREADS 1
diff --git a/firmware/export/imx31l.h b/firmware/export/imx31l.h
index aea4b9e151..777fa6981c 100755
--- a/firmware/export/imx31l.h
+++ b/firmware/export/imx31l.h
@@ -49,7 +49,7 @@
49#define ETB_SLOT4_BASE_ADDR 0x43F10000 49#define ETB_SLOT4_BASE_ADDR 0x43F10000
50#define ETB_SLOT5_BASE_ADDR 0x43F14000 50#define ETB_SLOT5_BASE_ADDR 0x43F14000
51#define ECT_CTIO_BASE_ADDR 0x43F18000 51#define ECT_CTIO_BASE_ADDR 0x43F18000
52#define I2C_BASE_ADDR 0x43F80000 52#define I2C1_BASE_ADDR 0x43F80000
53#define I2C3_BASE_ADDR 0x43F84000 53#define I2C3_BASE_ADDR 0x43F84000
54#define OTG_BASE_ADDR 0x43F88000 54#define OTG_BASE_ADDR 0x43F88000
55#define ATA_BASE_ADDR 0x43F8C000 55#define ATA_BASE_ADDR 0x43F8C000
@@ -628,6 +628,112 @@
628#define CSPI_TESTREG_SWAP (1 << 15) 628#define CSPI_TESTREG_SWAP (1 << 15)
629#define CSPI_TESTREG_LBC (1 << 14) 629#define CSPI_TESTREG_LBC (1 << 14)
630 630
631/* I2C */
632#define I2C_IADR1 (*(REG16_PTR_T)(I2C1_BASE_ADDR+0x0))
633#define I2C_IFDR1 (*(REG16_PTR_T)(I2C1_BASE_ADDR+0x4))
634#define I2C_I2CR1 (*(REG16_PTR_T)(I2C1_BASE_ADDR+0x8))
635#define I2C_I2SR1 (*(REG16_PTR_T)(I2C1_BASE_ADDR+0xC))
636#define I2C_I2DR1 (*(REG16_PTR_T)(I2C1_BASE_ADDR+0x10))
637
638#define I2C_IADR2 (*(REG16_PTR_T)(I2C2_BASE_ADDR+0x0))
639#define I2C_IFDR2 (*(REG16_PTR_T)(I2C2_BASE_ADDR+0x4))
640#define I2C_I2CR2 (*(REG16_PTR_T)(I2C2_BASE_ADDR+0x8))
641#define I2C_I2SR2 (*(REG16_PTR_T)(I2C2_BASE_ADDR+0xC))
642#define I2C_I2DR2 (*(REG16_PTR_T)(I2C2_BASE_ADDR+0x10))
643
644#define I2C_IADR3 (*(REG16_PTR_T)(I2C3_BASE_ADDR+0x0))
645#define I2C_IFDR3 (*(REG16_PTR_T)(I2C3_BASE_ADDR+0x4))
646#define I2C_I2CR3 (*(REG16_PTR_T)(I2C3_BASE_ADDR+0x8))
647#define I2C_I2SR3 (*(REG16_PTR_T)(I2C3_BASE_ADDR+0xC))
648#define I2C_I2DR3 (*(REG16_PTR_T)(I2C3_BASE_ADDR+0x10))
649
650 /* IADR - [7:1] Address */
651
652 /* IFDR */
653#define I2C_IFDR_DIV30 0x00
654#define I2C_IFDR_DIV32 0x01
655#define I2C_IFDR_DIV36 0x02
656#define I2C_IFDR_DIV42 0x03
657#define I2C_IFDR_DIV48 0x04
658#define I2C_IFDR_DIV52 0x05
659#define I2C_IFDR_DIV60 0x06
660#define I2C_IFDR_DIV72 0x07
661#define I2C_IFDR_DIV80 0x08
662#define I2C_IFDR_DIV88 0x09
663#define I2C_IFDR_DIV104 0x0a
664#define I2C_IFDR_DIV128 0x0b
665#define I2C_IFDR_DIV144 0x0c
666#define I2C_IFDR_DIV160 0x0d
667#define I2C_IFDR_DIV192 0x0e
668#define I2C_IFDR_DIV240 0x0f
669#define I2C_IFDR_DIV288 0x10
670#define I2C_IFDR_DIV320 0x11
671#define I2C_IFDR_DIV384 0x12
672#define I2C_IFDR_DIV480 0x13
673#define I2C_IFDR_DIV576 0x14
674#define I2C_IFDR_DIV640 0x15
675#define I2C_IFDR_DIV768 0x16
676#define I2C_IFDR_DIV960 0x17
677#define I2C_IFDR_DIV1152 0x18
678#define I2C_IFDR_DIV1280 0x19
679#define I2C_IFDR_DIV1536 0x1a
680#define I2C_IFDR_DIV1920 0x1b
681#define I2C_IFDR_DIV2304 0x1c
682#define I2C_IFDR_DIV2560 0x1d
683#define I2C_IFDR_DIV3072 0x1e
684#define I2C_IFDR_DIV3840 0x1f
685#define I2C_IFDR_DIV22 0x20
686#define I2C_IFDR_DIV24 0x21
687#define I2C_IFDR_DIV26 0x22
688#define I2C_IFDR_DIV28 0x23
689#define I2C_IFDR_DIV32_2 0x24
690#define I2C_IFDR_DIV36_2 0x25
691#define I2C_IFDR_DIV40 0x26
692#define I2C_IFDR_DIV44 0x27
693#define I2C_IFDR_DIV48_2 0x28
694#define I2C_IFDR_DIV56 0x29
695#define I2C_IFDR_DIV64 0x2a
696#define I2C_IFDR_DIV72_2 0x2b
697#define I2C_IFDR_DIV80_2 0x2c
698#define I2C_IFDR_DIV96 0x2d
699#define I2C_IFDR_DIV112 0x2e
700#define I2C_IFDR_DIV128_2 0x2f
701#define I2C_IFDR_DIV160_2 0x30
702#define I2C_IFDR_DIV192_2 0x31
703#define I2C_IFDR_DIV224 0x32
704#define I2C_IFDR_DIV256 0x33
705#define I2C_IFDR_DIV320_2 0x34
706#define I2C_IFDR_DIV384_2 0x35
707#define I2C_IFDR_DIV448 0x36
708#define I2C_IFDR_DIV512 0x37
709#define I2C_IFDR_DIV640_2 0x38
710#define I2C_IFDR_DIV768_2 0x39
711#define I2C_IFDR_DIV896 0x3a
712#define I2C_IFDR_DIV1024 0x3b
713#define I2C_IFDR_DIV1280_2 0x3c
714#define I2C_IFDR_DIV1536_2 0x3d
715#define I2C_IFDR_DIV1792 0x3e
716#define I2C_IFDR_DIV2048 0x3f
717
718 /* I2CR */
719#define I2C_I2CR_IEN (1 << 7)
720#define I2C_I2CR_IIEN (1 << 6)
721#define I2C_I2CR_MSTA (1 << 5)
722#define I2C_I2CR_MTX (1 << 4)
723#define I2C_I2CR_TXAK (1 << 3)
724#define I2C_I2CR_RSATA (1 << 2)
725
726 /* I2SR */
727#define I2C_I2SR_ICF (1 << 7)
728#define I2C_I2SR_IAAS (1 << 6)
729#define I2C_I2SR_IBB (1 << 5)
730#define I2C_I2SR_IAL (1 << 4)
731#define I2C_I2SR_SRW (1 << 2)
732#define I2C_I2SR_IIF (1 << 1)
733#define I2C_I2SR_RXAK (1 << 0)
734
735 /* I2DR - [7:0] Data */
736
631/* RTC */ 737/* RTC */
632#define RTC_HOURMIN (*(REG32_PTR_T)(RTC_BASE_ADDR+0x00)) 738#define RTC_HOURMIN (*(REG32_PTR_T)(RTC_BASE_ADDR+0x00))
633#define RTC_SECONDS (*(REG32_PTR_T)(RTC_BASE_ADDR+0x04)) 739#define RTC_SECONDS (*(REG32_PTR_T)(RTC_BASE_ADDR+0x04))
diff --git a/firmware/export/wm8978.h b/firmware/export/wm8978.h
index 3a1eb627df..aca1250665 100644
--- a/firmware/export/wm8978.h
+++ b/firmware/export/wm8978.h
@@ -21,6 +21,9 @@
21#ifndef _WM8978_H 21#ifndef _WM8978_H
22#define _WM8978_H 22#define _WM8978_H
23 23
24#define VOLUME_MIN -570
25#define VOLUME_MAX 60
26
24#define WM8978_I2C_ADDR 0x34 27#define WM8978_I2C_ADDR 0x34
25 28
26/* Registers */ 29/* Registers */
@@ -142,7 +145,7 @@
142 #define WM8978_DAC_COMP_U_LAW (2 << 3) 145 #define WM8978_DAC_COMP_U_LAW (2 << 3)
143 #define WM8978_DAC_COMP_A_LAW (3 << 3) 146 #define WM8978_DAC_COMP_A_LAW (3 << 3)
144#define WM8978_ADC_COMP (3 << 1) 147#define WM8978_ADC_COMP (3 << 1)
145 #define WM8978_DAC_COMP_OFF (0 << 1) 148 #define WM8978_ADC_COMP_OFF (0 << 1)
146 #define WM8978_ADC_COMP_U_LAW (2 << 1) 149 #define WM8978_ADC_COMP_U_LAW (2 << 1)
147 #define WM8978_ADC_COMP_A_LAW (3 << 1) 150 #define WM8978_ADC_COMP_A_LAW (3 << 1)
148#define WM8978_LOOPBACK (1 << 0) 151#define WM8978_LOOPBACK (1 << 0)
@@ -159,12 +162,12 @@
159 #define WM8978_MCLKDIV_8 (6 << 5) 162 #define WM8978_MCLKDIV_8 (6 << 5)
160 #define WM8978_MCLKDIV_12 (7 << 5) 163 #define WM8978_MCLKDIV_12 (7 << 5)
161#define WM8978_BCLKDIV (7 << 2) 164#define WM8978_BCLKDIV (7 << 2)
162 #define WM8978_MCLKDIV_1 (0 << 2) 165 #define WM8978_BCLKDIV_1 (0 << 2)
163 #define WM8978_MCLKDIV_2 (1 << 2) 166 #define WM8978_BCLKDIV_2 (1 << 2)
164 #define WM8978_MCLKDIV_4 (2 << 2) 167 #define WM8978_BCLKDIV_4 (2 << 2)
165 #define WM8978_MCLKDIV_8 (3 << 2) 168 #define WM8978_BCLKDIV_8 (3 << 2)
166 #define WM8978_MCLKDIV_16 (4 << 2) 169 #define WM8978_BCLKDIV_16 (4 << 2)
167 #define WM8978_MCLKDIV_32 (5 << 2) 170 #define WM8978_BCLKDIV_32 (5 << 2)
168#define WM8978_MS (1 << 0) 171#define WM8978_MS (1 << 0)
169 172
170/* WM8978_ADDITIONAL_CTRL (0x07) */ 173/* WM8978_ADDITIONAL_CTRL (0x07) */
diff --git a/firmware/target/arm/imx31/gigabeat-s/i2c-imx31.c b/firmware/target/arm/imx31/gigabeat-s/i2c-imx31.c
index 54ddaa7a46..ccd9efb321 100644
--- a/firmware/target/arm/imx31/gigabeat-s/i2c-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/i2c-imx31.c
@@ -7,7 +7,7 @@
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2007 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.
@@ -16,38 +16,321 @@
16 * KIND, either express or implied. 16 * KIND, either express or implied.
17 * 17 *
18 ****************************************************************************/ 18 ****************************************************************************/
19#include <stdlib.h>
20#include "config.h"
19#include "system.h" 21#include "system.h"
22#include "kernel.h"
23#include "avic-imx31.h"
24#include "clkctl-imx31.h"
20#include "i2c-imx31.h" 25#include "i2c-imx31.h"
21 26
22#if 0 27/* Forward interrupt handler declarations */
23static int i2c_getack(void) 28#if (I2C_MODULE_MASK & USE_I2C1_MODULE)
29static __attribute__((interrupt("IRQ"))) void I2C1_HANDLER(void);
30#endif
31#if (I2C_MODULE_MASK & USE_I2C2_MODULE)
32static __attribute__((interrupt("IRQ"))) void I2C2_HANDLER(void);
33#endif
34#if (I2C_MODULE_MASK & USE_I2C3_MODULE)
35static __attribute__((interrupt("IRQ"))) void I2C3_HANDLER(void);
36#endif
37
38static struct i2c_module_descriptor
24{ 39{
25 return 0; 40 struct i2c_map *base; /* Module base address */
41 enum IMX31_CG_LIST cg; /* Clock gating index */
42 enum IMX31_INT_LIST ints; /* Module interrupt number */
43 int enable; /* Enable count */
44 void (*handler)(void); /* Module interrupt handler */
45 struct mutex m; /* Node mutual-exclusion */
46 struct wakeup w; /* I2C done signal */
47 unsigned char *addr_data; /* Additional addressing data */
48 int addr_count; /* Addressing byte count */
49 unsigned char *data; /* TX/RX buffer (actual data) */
50 int data_count; /* TX/RX byte count */
51 unsigned char addr; /* Address + r/w bit */
52} i2c_descs[I2C_NUM_I2C] =
53{
54#if (I2C_MODULE_MASK & USE_I2C1_MODULE)
55 {
56 .base = (struct i2c_map *)I2C1_BASE_ADDR,
57 .cg = CG_I2C1,
58 .ints = I2C1,
59 .handler = I2C1_HANDLER,
60 },
61#endif
62#if (I2C_MODULE_MASK & USE_I2C2_MODULE)
63 {
64 .base = (struct i2c_map *)I2C2_BASE_ADDR,
65 .cg = CG_I2C2,
66 .ints = I2C2,
67 .handler = I2C2_HANDLER,
68 },
69#endif
70#if (I2C_MODULE_MASK & USE_I2C3_MODULE)
71 {
72 .base = (struct i2c_map *)I2C3_BASE_ADDR,
73 .cg = CG_I2C3,
74 .ints = I2C3,
75 .handler = I2C3_HANDLER,
76 },
77#endif
78};
79
80static void i2c_interrupt(enum i2c_module_number i2c)
81{
82 struct i2c_module_descriptor *const desc = &i2c_descs[i2c];
83 struct i2c_map * const base = desc->base;
84 uint16_t i2sr = base->i2sr;
85
86 base->i2sr = i2sr & ~I2C_I2SR_IIF; /* Clear IIF */
87
88 if (desc->addr_count >= 0)
89 {
90 /* ADDR cycle - either done or more to send */
91 if ((i2sr & I2C_I2SR_RXAK) != 0)
92 {
93 goto i2c_stop; /* problem */
94 }
95
96 if (--desc->addr_count < 0)
97 {
98 /* Switching to data cycle */
99 if (desc->addr & 0x1)
100 {
101 base->i2cr &= ~I2C_I2CR_MTX; /* Switch to RX mode */
102 base->i2dr; /* Dummy read */
103 return;
104 }
105 /* else remaining data is TX - handle below */
106 goto i2c_transmit;
107 }
108 else
109 {
110 base->i2dr = *desc->addr_data++; /* Send next addressing byte */
111 return;
112 }
113 }
114
115 if (base->i2cr & I2C_I2CR_MTX)
116 {
117i2c_transmit:
118 /* Transmitting data */
119 if ((i2sr & I2C_I2SR_RXAK) == 0 && desc->data_count > 0)
120 {
121 /* More bytes to send, got ACK from previous byte */
122 base->i2dr = *desc->data++;
123 desc->data_count--;
124 return;
125 }
126 /* else done or no ACK received */
127 }
128 else
129 {
130 /* Receiving data */
131 if (--desc->data_count > 0)
132 {
133 if (desc->data_count == 1)
134 {
135 /* 2nd to Last byte - NACK */
136 base->i2cr |= I2C_I2CR_TXAK;
137 }
138
139 *desc->data++ = base->i2dr; /* Read data from I2DR and store */
140 return;
141 }
142 else
143 {
144 /* Generate STOP signal before reading data */
145 base->i2cr &= ~(I2C_I2CR_MSTA | I2C_I2CR_IIEN);
146 *desc->data++ = base->i2dr; /* Read data from I2DR and store */
147 goto i2c_done;
148 }
149 }
150
151i2c_stop:
152 /* Generate STOP signal */
153 base->i2cr &= ~(I2C_I2CR_MSTA | I2C_I2CR_IIEN);
154i2c_done:
155 /* Signal thread we're done */
156 wakeup_signal(&desc->w);
26} 157}
27 158
28static int i2c_start(void) 159#if (I2C_MODULE_MASK & USE_I2C1_MODULE)
160static __attribute__((interrupt("IRQ"))) void I2C1_HANDLER(void)
29{ 161{
30 return 0; 162 i2c_interrupt(I2C1_NUM);
31} 163}
164#endif
165#if (I2C_MODULE_MASK & USE_I2C2_MODULE)
166static __attribute__((interrupt("IRQ"))) void I2C2_HANDLER(void)
167{
168 i2c_interrupt(I2C2_NUM);
169}
170#endif
171#if (I2C_MODULE_MASK & USE_I2C3_MODULE)
172static __attribute__((interrupt("IRQ"))) void I2C3_HANDLER(void)
173{
174 i2c_interrupt(I2C3_NUM);
175}
176#endif
32 177
33static void i2c_stop(void) 178static int i2c_transfer(struct i2c_node * const node,
179 struct i2c_module_descriptor *const desc)
34{ 180{
181 struct i2c_map * const base = desc->base;
182 int count = desc->data_count;
183 uint16_t i2cr;
184
185 /* Set speed */
186 base->ifdr = node->ifdr;
187
188 /* Enable module */
189 base->i2cr = I2C_I2CR_IEN;
190
191 /* Enable Interrupt, Master */
192 i2cr = I2C_I2CR_IEN | I2C_I2CR_IIEN | I2C_I2CR_MTX;
193
194 if ((desc->addr & 0x1) && desc->data_count < 2)
195 {
196 /* Receiving less than two bytes - disable ACK generation */
197 i2cr |= I2C_I2CR_TXAK;
198 }
199
200 /* Set config */
201 base->i2cr = i2cr;
202
203 /* Generate START */
204 base->i2cr |= I2C_I2CR_MSTA;
205
206 /* Address slave (first byte sent) and begin session. */
207 base->i2dr = desc->addr;
208
209 /* Wait for transfer to complete */
210 count = (wakeup_wait(&desc->w, HZ) != OBJ_WAIT_SUCCEEDED) ?
211 -1 : (count - desc->data_count);
212
213 /* Disable module - generate STOP if timeout */
214 base->i2cr = 0;
215
216 return count;
35} 217}
36 218
37static int i2c_outb(unsigned char byte) 219int i2c_read(struct i2c_node *node, int reg,
220 unsigned char *data, int data_count)
38{ 221{
39 (void)byte; 222 struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
40 return 0; 223 unsigned char ad[1];
224
225 mutex_lock(&desc->m);
226
227 desc->addr = (node->addr & 0xfe) | 0x1; /* Slave address/rd */
228
229 if (reg >= 0)
230 {
231 /* Sub-address */
232 desc->addr_count = 1;
233 desc->addr_data = ad;
234 ad[0] = reg;
235 }
236 /* else raw read from slave */
237
238 desc->data = data;
239 desc->data_count = data_count;
240
241 data_count = i2c_transfer(node, desc);
242
243 desc->addr_count = 0; /* To eliminate zeroing elsewhere */
244
245 mutex_unlock(&desc->m);
246
247 return data_count;
41} 248}
42#endif
43 249
44void i2c_write(int addr, const unsigned char *buf, int count) 250int i2c_write(struct i2c_node *node, const unsigned char *data, int data_count)
45{ 251{
46 (void)addr; 252 struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
47 (void)buf; 253
48 (void)count; 254 mutex_lock(&desc->m);
255
256 desc->addr = node->addr & 0xfe; /* Slave address/wr */
257 desc->data = (unsigned char *)data;
258 desc->data_count = data_count;
259
260 data_count = i2c_transfer(node, desc);
261
262 mutex_unlock(&desc->m);
263
264 return data_count;
49} 265}
50 266
51void i2c_init(void) 267void i2c_init(void)
52{ 268{
269 int i;
270
271 /* Do one-time inits for each module that will be used - leave
272 * module disabled and unclocked until something wants it */
273 for (i = 0; i < I2C_NUM_I2C; i++)
274 {
275 struct i2c_module_descriptor *const desc = &i2c_descs[i];
276 imx31_clkctl_module_clock_gating(desc->cg, CGM_ON_ALL);
277 mutex_init(&desc->m);
278 wakeup_init(&desc->w);
279 desc->base->i2cr = 0;
280 imx31_clkctl_module_clock_gating(desc->cg, CGM_OFF);
281 }
282
283#if 0
284 /* Pad config set up by OF bootloader doesn't agree with manual but
285 * TX works at the moment - probably would't do this here either */
286 uint32_t reg = SW_PAD_CTL_CSI_PIXCLK_I2C_CLK_I2C_DAT;
287 reg &= ~0xfffff;
288 reg |= (1 << 19) | (3 << 17) | (1 << 15) | (1 << 14) |
289 (1 << 13) | (0 << 11);
290
291 reg |= (1 << 9) | (3 << 7) | (1 << 5) | (1 << 4) |
292 (1 << 3) | (0 << 1);
293
294 SW_PAD_CTL_CSI_PIXCLK_I2C_CLK_I2C_DAT = reg;
295#endif
296}
297
298void i2c_enable_node(struct i2c_node *node, bool enable)
299{
300 struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
301
302 mutex_lock(&desc->m);
303
304 if (enable)
305 {
306 if (++desc->enable == 1)
307 {
308 /* First enable */
309 imx31_clkctl_module_clock_gating(desc->cg, CGM_ON_ALL);
310 avic_enable_int(desc->ints, IRQ, 7, desc->handler);
311 }
312 }
313 else
314 {
315 if (desc->enable > 0 && --desc->enable == 0)
316 {
317 /* Last enable */
318 avic_disable_int(desc->ints);
319 imx31_clkctl_module_clock_gating(desc->cg, CGM_OFF);
320 }
321 }
322
323 mutex_unlock(&desc->m);
324}
325
326void i2c_lock_node(struct i2c_node *node)
327{
328 struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
329 mutex_lock(&desc->m);
330}
331
332void i2c_unlock_node(struct i2c_node *node)
333{
334 struct i2c_module_descriptor *const desc = &i2c_descs[node->num];
335 mutex_unlock(&desc->m);
53} 336}
diff --git a/firmware/target/arm/imx31/gigabeat-s/i2c-imx31.h b/firmware/target/arm/imx31/gigabeat-s/i2c-imx31.h
index c708ebbfb4..d6de5c47e8 100644
--- a/firmware/target/arm/imx31/gigabeat-s/i2c-imx31.h
+++ b/firmware/target/arm/imx31/gigabeat-s/i2c-imx31.h
@@ -16,7 +16,61 @@
16 * KIND, either express or implied. 16 * KIND, either express or implied.
17 * 17 *
18 ****************************************************************************/ 18 ****************************************************************************/
19#ifndef _I2C_IMX31_H_
20#define _I2C_IMX31_H_
21
22#include <stdbool.h>
23
24/* I2C module usage masks */
25#define USE_I2C1_MODULE (1 << 0)
26#define USE_I2C2_MODULE (1 << 1)
27#define USE_I2C3_MODULE (1 << 2)
28
29enum i2c_module_number
30{
31 __I2C_NUM_START = -1,
32#if (I2C_MODULE_MASK & USE_I2C1_MODULE)
33 I2C1_NUM,
34#endif
35#if (I2C_MODULE_MASK & USE_I2C2_MODULE)
36 I2C2_NUM,
37#endif
38#if (I2C_MODULE_MASK & USE_I2C3_MODULE)
39 I2C3_NUM,
40#endif
41 I2C_NUM_I2C,
42};
43
44/* Module interface map structure */
45struct i2c_map
46{
47 volatile uint16_t iadr; /* 0x00 */
48 volatile uint16_t unused1;
49 volatile uint16_t ifdr; /* 0x04 */
50 volatile uint16_t unused2;
51 volatile uint16_t i2cr; /* 0x08 */
52 volatile uint16_t unused3;
53 volatile uint16_t i2sr; /* 0x0C */
54 volatile uint16_t unused4;
55 volatile uint16_t i2dr; /* 0x10 */
56};
57
58struct i2c_node
59{
60 enum i2c_module_number num; /* Module that this node uses */
61 unsigned int ifdr; /* Maximum frequency for node */
62 unsigned char addr; /* Slave address on module */
63};
19 64
20void i2c_init(void); 65void i2c_init(void);
21void i2c_write(int addr, const unsigned char *data, int count); 66/* Enable or disable the node - modules will be switch on/off accordingly. */
67void i2c_enable_node(struct i2c_node *node, bool enable);
68/* If addr < 0, then raw read */
69int i2c_read(struct i2c_node *node, int addr, unsigned char *data, int count);
70int i2c_write(struct i2c_node *node, const unsigned char *data, int count);
71/* Gain mutually-exclusive access to the node and module to perform multiple
72 * operations atomically */
73void i2c_lock_node(struct i2c_node *node);
74void i2c_unlock_node(struct i2c_node *node);
22 75
76#endif /* _I2C_IMX31_H_ */
diff --git a/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c b/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c
index 4d2206bd56..e37f6bfbe2 100644
--- a/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c
@@ -49,10 +49,12 @@ void pcm_apply_settings(void)
49 49
50void pcm_play_dma_init(void) 50void pcm_play_dma_init(void)
51{ 51{
52 audiohw_init();
52} 53}
53 54
54void pcm_postinit(void) 55void pcm_postinit(void)
55{ 56{
57 audiohw_postinit();
56} 58}
57 59
58#if 0 60#if 0
diff --git a/firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c b/firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c
index 238ee3aeb2..235ae54bad 100644
--- a/firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/wmcodec-imx31.c
@@ -7,7 +7,7 @@
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Gigabeat specific code for the Wolfson codec 10 * Gigabeat S specific code for the WM8978 codec
11 * 11 *
12 * Based on code from the ipodlinux project - http://ipodlinux.org/ 12 * Based on code from the ipodlinux project - http://ipodlinux.org/
13 * Adapted for Rockbox in December 2005 13 * Adapted for Rockbox in December 2005
@@ -28,12 +28,31 @@
28#include "sound.h" 28#include "sound.h"
29#include "i2c-imx31.h" 29#include "i2c-imx31.h"
30 30
31/* NOTE: Some port-specific bits will have to be moved away (node and GPIO
32 * writes) for cleanest implementation. */
33
34static struct i2c_node wm8978_i2c_node =
35{
36 .num = I2C1_NUM,
37 .ifdr = I2C_IFDR_DIV192, /* 66MHz/.4MHz = 165, closest = 192 = 343750Hz */
38 /* Just hard-code for now - scaling may require
39 * updating */
40 .addr = WM8978_I2C_ADDR,
41};
42
31void audiohw_init(void) 43void audiohw_init(void)
32{ 44{
45 i2c_enable_node(&wm8978_i2c_node, true);
46 GPIO3_DR |= (1 << 21); /* Turn on analogue LDO */
47 sleep(HZ/10); /* Wait for things to stabilize */
48 audiohw_preinit();
33} 49}
34 50
35void wmcodec_write(int reg, int data) 51void wmcodec_write(int reg, int data)
36{ 52{
37 (void)reg; 53 unsigned char d[2];
38 (void)data; 54 /* |aaaaaaad|dddddddd| */
55 d[0] = (reg << 1) | ((data & 0x100) >> 8);
56 d[1] = data;
57 i2c_write(&wm8978_i2c_node, d, 2);
39} 58}