diff options
Diffstat (limited to 'firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c')
-rw-r--r-- | firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c | 201 |
1 files changed, 90 insertions, 111 deletions
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c index e69eab432a..c207e310d9 100644 --- a/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c +++ b/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c | |||
@@ -1,6 +1,5 @@ | |||
1 | #include "config.h" | 1 | #include "config.h" |
2 | #include "cpu.h" | 2 | #include "cpu.h" |
3 | #include <stdbool.h> | ||
4 | #include "kernel.h" | 3 | #include "kernel.h" |
5 | #include "system.h" | 4 | #include "system.h" |
6 | #include "logf.h" | 5 | #include "logf.h" |
@@ -9,147 +8,132 @@ | |||
9 | 8 | ||
10 | #define SLAVE_ADDRESS 0xCC | 9 | #define SLAVE_ADDRESS 0xCC |
11 | 10 | ||
12 | #define SDA_LO (GPHDAT &= ~(1 << 9)) | 11 | #define USE_ASM |
13 | #define SDA_HI (GPHDAT |= (1 << 9)) | 12 | |
14 | #define SDA_INPUT (GPHCON &= ~(3 << 18)) | 13 | /* This I2C driver tristates the outputs instead of driving logic high's */ |
15 | #define SDA_OUTPUT (GPHCON |= (1 << 18)) | ||
16 | #define SDA (GPHDAT & (1 << 9)) | 14 | #define SDA (GPHDAT & (1 << 9)) |
15 | #define SDA_LO_OUT (GPHCON |= (1 << 18));(GPHDAT &= ~(1 << 9)); | ||
16 | #define SDA_HI_IN (GPHCON &= ~(3 << 18)) | ||
17 | 17 | ||
18 | #define SCL_LO (GPHDAT &= ~(1 << 10)) | ||
19 | #define SCL_HI (GPHDAT |= (1 << 10)) | ||
20 | #define SCL_INPUT (GPHCON &= ~(3 << 20)) | ||
21 | #define SCL_OUTPUT (GPHCON |= (1 << 20)) | ||
22 | #define SCL (GPHDAT & (1 << 10)) | 18 | #define SCL (GPHDAT & (1 << 10)) |
23 | 19 | #define SCL_LO_OUT (GPHCON |= (1 << 20));(GPHDAT &= ~(1 << 10)); | |
24 | #define SCL_SDA_HI (GPHDAT |= (3 << 9)) | 20 | #define SCL_HI_IN (GPHCON &= ~(3 << 20));while(!SCL); |
25 | 21 | ||
26 | /* The SC606 can clock at 400KHz: */ | 22 | /* The SC606 can clock at 400KHz: |
27 | /* Clock period high is 600nS and low is 1300nS */ | 23 | * Clock period high is 600nS and low is 1300nS |
28 | /* The high and low times are different enough to need different timings */ | 24 | * The high and low times are different enough to need different timings |
29 | /* cycles delayed = 30 + 7 * loops */ | 25 | * cycles delayed = 2 + 4 * loops |
30 | /* 100MHz = 10nS per cycle: LO:1300nS=130:14 HI:600nS=60:9 */ | 26 | * 100MHz = 10nS per cycle: LO:1300nS=130:33 HI:600nS=60:15 |
31 | /* 300MHz = 3.36nS per cycle: LO:1300nS=387:51 HI:600nS=179:21 */ | 27 | * 300MHz = 3.33nS per cycle: |
32 | #define DELAY_LO do{int x;for(x=51;x;x--);} while (0) | 28 | * LO:1300nS=394:99 |
33 | #define DELAY do{int x;for(x=35;x;x--);} while (0) | 29 | * HI:600nS=182:21 |
34 | #define DELAY_HI do{int x;for(x=21;x;x--);} while (0) | 30 | * MID(50/50):950(1900/2)ns=288:72 |
35 | 31 | */ | |
36 | 32 | ||
33 | #ifdef USE_ASM | ||
34 | |||
35 | #define DELAY_LO 99 | ||
36 | #define DELAY_MID 72 | ||
37 | #define DELAY_HI 46 | ||
38 | /* This delay loop takes 4 cycles/loop to execute plus 2 for setup */ | ||
39 | #define DELAY(dly) \ | ||
40 | asm volatile( "mov r0,%0 \n" \ | ||
41 | "1: \n" \ | ||
42 | "subs r0,r0,#1 \n" \ | ||
43 | "bhi 1b \n" \ | ||
44 | : : "r"((dly)) : "r0" ); | ||
45 | |||
46 | #else | ||
47 | |||
48 | #define DELAY_LO 51 | ||
49 | #define DELAY_MID 35 | ||
50 | #define DELAY_HI 21 | ||
51 | #define DELAY(dly) do{int x;for(x=(dly);x;x--);} while (0) | ||
52 | |||
53 | #endif | ||
37 | 54 | ||
38 | static void sc606_i2c_start(void) | 55 | static void sc606_i2c_start(void) |
39 | { | 56 | { |
40 | SCL_SDA_HI; | 57 | SDA_HI_IN; |
41 | DELAY; | 58 | SCL_HI_IN; |
42 | SDA_LO; | 59 | DELAY(DELAY_MID); |
43 | DELAY; | 60 | SDA_LO_OUT; |
44 | SCL_LO; | 61 | DELAY(DELAY_MID); |
45 | } | 62 | SCL_LO_OUT; |
46 | |||
47 | static void sc606_i2c_restart(void) | ||
48 | { | ||
49 | SCL_SDA_HI; | ||
50 | DELAY; | ||
51 | SDA_LO; | ||
52 | DELAY; | ||
53 | SCL_LO; | ||
54 | } | 63 | } |
55 | 64 | ||
56 | static void sc606_i2c_stop(void) | 65 | static void sc606_i2c_stop(void) |
57 | { | 66 | { |
58 | SDA_LO; | 67 | SDA_LO_OUT; |
59 | SCL_HI; | 68 | SCL_HI_IN; |
60 | DELAY_HI; | 69 | DELAY(DELAY_HI); |
61 | SDA_HI; | 70 | SDA_HI_IN; |
62 | } | 71 | } |
63 | 72 | ||
64 | static void sc606_i2c_ack(void) | 73 | static void sc606_i2c_ack(void) |
65 | { | 74 | { |
75 | SDA_HI_IN; | ||
76 | SCL_HI_IN; | ||
66 | 77 | ||
67 | SDA_LO; | 78 | DELAY(DELAY_HI); |
68 | SCL_HI; | 79 | SCL_LO_OUT; |
69 | DELAY_HI; | ||
70 | SCL_LO; | ||
71 | } | 80 | } |
72 | 81 | ||
73 | 82 | static bool sc606_i2c_getack(void) | |
74 | |||
75 | static int sc606_i2c_getack(void) | ||
76 | { | 83 | { |
77 | int ret; | 84 | bool ret; |
78 | |||
79 | /* Don't need a delay since follows a data bit with a delay on the end */ | ||
80 | SDA_INPUT; /* And set to input */ | ||
81 | DELAY; | ||
82 | SCL_HI; | ||
83 | 85 | ||
84 | ret = (SDA != 0); /* ack failed if SDA is not low */ | 86 | SDA_HI_IN; |
85 | DELAY_HI; | 87 | DELAY(DELAY_MID); |
88 | SCL_HI_IN; | ||
86 | 89 | ||
87 | SCL_LO; | 90 | ret = !SDA; |
88 | DELAY_LO; | ||
89 | 91 | ||
90 | SDA_HI; | 92 | SCL_LO_OUT; |
91 | SDA_OUTPUT; | 93 | DELAY(DELAY_LO); |
92 | DELAY_LO; | ||
93 | 94 | ||
94 | return ret; | 95 | return ret; |
95 | } | 96 | } |
96 | 97 | ||
97 | |||
98 | |||
99 | static void sc606_i2c_outb(unsigned char byte) | 98 | static void sc606_i2c_outb(unsigned char byte) |
100 | { | 99 | { |
101 | int i; | 100 | int i; |
102 | 101 | ||
103 | /* clock out each bit, MSB first */ | 102 | /* clock out each bit, MSB first */ |
104 | for (i = 0x80; i; i >>= 1) | 103 | for ( i=0x80; i; i>>=1 ) |
105 | { | 104 | { |
106 | if (i & byte) | 105 | if ( i & byte ) |
107 | { | 106 | SDA_HI_IN; |
108 | SDA_HI; | ||
109 | } | ||
110 | else | 107 | else |
111 | { | 108 | SDA_LO_OUT; |
112 | SDA_LO; | 109 | DELAY(DELAY_MID); |
113 | } | 110 | SCL_HI_IN; |
114 | DELAY; | 111 | DELAY(DELAY_HI); |
115 | 112 | SCL_LO_OUT; | |
116 | SCL_HI; | ||
117 | DELAY_HI; | ||
118 | |||
119 | SCL_LO; | ||
120 | DELAY_LO; | ||
121 | } | 113 | } |
122 | |||
123 | SDA_HI; | ||
124 | |||
125 | } | 114 | } |
126 | 115 | ||
127 | |||
128 | |||
129 | static unsigned char sc606_i2c_inb(void) | 116 | static unsigned char sc606_i2c_inb(void) |
130 | { | 117 | { |
131 | int i; | 118 | int i; |
132 | unsigned char byte = 0; | 119 | unsigned char byte = 0; |
133 | |||
134 | SDA_INPUT; /* And set to input */ | ||
135 | /* clock in each bit, MSB first */ | ||
136 | for (i = 0x80; i; i >>= 1) { | ||
137 | SCL_HI; | ||
138 | |||
139 | if (SDA) | ||
140 | byte |= i; | ||
141 | |||
142 | SCL_LO; | ||
143 | } | ||
144 | SDA_OUTPUT; | ||
145 | 120 | ||
146 | sc606_i2c_ack(); | 121 | /* clock in each bit, MSB first */ |
122 | SDA_HI_IN; | ||
123 | for ( i=0x80; i; i>>=1 ) | ||
124 | { | ||
125 | SCL_HI_IN; | ||
126 | DELAY(DELAY_HI); | ||
127 | if ( SDA ) | ||
128 | byte |= i; | ||
129 | SCL_LO_OUT; | ||
130 | DELAY(DELAY_LO); | ||
131 | } | ||
147 | 132 | ||
148 | return byte; | 133 | sc606_i2c_ack(); |
134 | return byte; | ||
149 | } | 135 | } |
150 | 136 | ||
151 | |||
152 | |||
153 | /* returns number of acks that were bad */ | 137 | /* returns number of acks that were bad */ |
154 | int sc606_write(unsigned char reg, unsigned char data) | 138 | int sc606_write(unsigned char reg, unsigned char data) |
155 | { | 139 | { |
@@ -163,7 +147,7 @@ int sc606_write(unsigned char reg, unsigned char data) | |||
163 | sc606_i2c_outb(reg); | 147 | sc606_i2c_outb(reg); |
164 | x += sc606_i2c_getack(); | 148 | x += sc606_i2c_getack(); |
165 | 149 | ||
166 | sc606_i2c_restart(); | 150 | sc606_i2c_start(); |
167 | 151 | ||
168 | sc606_i2c_outb(SLAVE_ADDRESS); | 152 | sc606_i2c_outb(SLAVE_ADDRESS); |
169 | x += sc606_i2c_getack(); | 153 | x += sc606_i2c_getack(); |
@@ -176,8 +160,6 @@ int sc606_write(unsigned char reg, unsigned char data) | |||
176 | return x; | 160 | return x; |
177 | } | 161 | } |
178 | 162 | ||
179 | |||
180 | |||
181 | int sc606_read(unsigned char reg, unsigned char* data) | 163 | int sc606_read(unsigned char reg, unsigned char* data) |
182 | { | 164 | { |
183 | int x; | 165 | int x; |
@@ -189,7 +171,7 @@ int sc606_read(unsigned char reg, unsigned char* data) | |||
189 | sc606_i2c_outb(reg); | 171 | sc606_i2c_outb(reg); |
190 | x += sc606_i2c_getack(); | 172 | x += sc606_i2c_getack(); |
191 | 173 | ||
192 | sc606_i2c_restart(); | 174 | sc606_i2c_start(); |
193 | sc606_i2c_outb(SLAVE_ADDRESS | 1); | 175 | sc606_i2c_outb(SLAVE_ADDRESS | 1); |
194 | x += sc606_i2c_getack(); | 176 | x += sc606_i2c_getack(); |
195 | 177 | ||
@@ -199,8 +181,6 @@ int sc606_read(unsigned char reg, unsigned char* data) | |||
199 | return x; | 181 | return x; |
200 | } | 182 | } |
201 | 183 | ||
202 | |||
203 | |||
204 | void sc606_init(void) | 184 | void sc606_init(void) |
205 | { | 185 | { |
206 | volatile int i; | 186 | volatile int i; |
@@ -214,12 +194,11 @@ void sc606_init(void) | |||
214 | 194 | ||
215 | /* About 400us - needs 350us */ | 195 | /* About 400us - needs 350us */ |
216 | for (i = 200; i; i--) | 196 | for (i = 200; i; i--) |
217 | { | 197 | DELAY(DELAY_LO); |
218 | DELAY_LO; | ||
219 | } | ||
220 | 198 | ||
221 | /* Set GPH9 (SDA) and GPH10 (SCL) to 1 */ | 199 | /* Set GPH9 (SDA) and GPH10 (SCL) to 1 */ |
222 | GPHUP &= ~(3<<9); | 200 | GPHUP &= ~(3<<9); |
223 | GPHCON = (GPHCON & ~(0xF<<18)) | 5<<18; | 201 | SCL_HI_IN; |
202 | SDA_HI_IN; | ||
224 | } | 203 | } |
225 | 204 | ||