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 | 225 |
1 files changed, 225 insertions, 0 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 new file mode 100644 index 0000000000..e69eab432a --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c | |||
@@ -0,0 +1,225 @@ | |||
1 | #include "config.h" | ||
2 | #include "cpu.h" | ||
3 | #include <stdbool.h> | ||
4 | #include "kernel.h" | ||
5 | #include "system.h" | ||
6 | #include "logf.h" | ||
7 | #include "debug.h" | ||
8 | #include "string.h" | ||
9 | |||
10 | #define SLAVE_ADDRESS 0xCC | ||
11 | |||
12 | #define SDA_LO (GPHDAT &= ~(1 << 9)) | ||
13 | #define SDA_HI (GPHDAT |= (1 << 9)) | ||
14 | #define SDA_INPUT (GPHCON &= ~(3 << 18)) | ||
15 | #define SDA_OUTPUT (GPHCON |= (1 << 18)) | ||
16 | #define SDA (GPHDAT & (1 << 9)) | ||
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)) | ||
23 | |||
24 | #define SCL_SDA_HI (GPHDAT |= (3 << 9)) | ||
25 | |||
26 | /* The SC606 can clock at 400KHz: */ | ||
27 | /* Clock period high is 600nS and low is 1300nS */ | ||
28 | /* The high and low times are different enough to need different timings */ | ||
29 | /* cycles delayed = 30 + 7 * loops */ | ||
30 | /* 100MHz = 10nS per cycle: LO:1300nS=130:14 HI:600nS=60:9 */ | ||
31 | /* 300MHz = 3.36nS per cycle: LO:1300nS=387:51 HI:600nS=179:21 */ | ||
32 | #define DELAY_LO do{int x;for(x=51;x;x--);} while (0) | ||
33 | #define DELAY do{int x;for(x=35;x;x--);} while (0) | ||
34 | #define DELAY_HI do{int x;for(x=21;x;x--);} while (0) | ||
35 | |||
36 | |||
37 | |||
38 | static void sc606_i2c_start(void) | ||
39 | { | ||
40 | SCL_SDA_HI; | ||
41 | DELAY; | ||
42 | SDA_LO; | ||
43 | DELAY; | ||
44 | SCL_LO; | ||
45 | } | ||
46 | |||
47 | static void sc606_i2c_restart(void) | ||
48 | { | ||
49 | SCL_SDA_HI; | ||
50 | DELAY; | ||
51 | SDA_LO; | ||
52 | DELAY; | ||
53 | SCL_LO; | ||
54 | } | ||
55 | |||
56 | static void sc606_i2c_stop(void) | ||
57 | { | ||
58 | SDA_LO; | ||
59 | SCL_HI; | ||
60 | DELAY_HI; | ||
61 | SDA_HI; | ||
62 | } | ||
63 | |||
64 | static void sc606_i2c_ack(void) | ||
65 | { | ||
66 | |||
67 | SDA_LO; | ||
68 | SCL_HI; | ||
69 | DELAY_HI; | ||
70 | SCL_LO; | ||
71 | } | ||
72 | |||
73 | |||
74 | |||
75 | static int sc606_i2c_getack(void) | ||
76 | { | ||
77 | int 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 | |||
84 | ret = (SDA != 0); /* ack failed if SDA is not low */ | ||
85 | DELAY_HI; | ||
86 | |||
87 | SCL_LO; | ||
88 | DELAY_LO; | ||
89 | |||
90 | SDA_HI; | ||
91 | SDA_OUTPUT; | ||
92 | DELAY_LO; | ||
93 | |||
94 | return ret; | ||
95 | } | ||
96 | |||
97 | |||
98 | |||
99 | static void sc606_i2c_outb(unsigned char byte) | ||
100 | { | ||
101 | int i; | ||
102 | |||
103 | /* clock out each bit, MSB first */ | ||
104 | for (i = 0x80; i; i >>= 1) | ||
105 | { | ||
106 | if (i & byte) | ||
107 | { | ||
108 | SDA_HI; | ||
109 | } | ||
110 | else | ||
111 | { | ||
112 | SDA_LO; | ||
113 | } | ||
114 | DELAY; | ||
115 | |||
116 | SCL_HI; | ||
117 | DELAY_HI; | ||
118 | |||
119 | SCL_LO; | ||
120 | DELAY_LO; | ||
121 | } | ||
122 | |||
123 | SDA_HI; | ||
124 | |||
125 | } | ||
126 | |||
127 | |||
128 | |||
129 | static unsigned char sc606_i2c_inb(void) | ||
130 | { | ||
131 | int i; | ||
132 | 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 | |||
146 | sc606_i2c_ack(); | ||
147 | |||
148 | return byte; | ||
149 | } | ||
150 | |||
151 | |||
152 | |||
153 | /* returns number of acks that were bad */ | ||
154 | int sc606_write(unsigned char reg, unsigned char data) | ||
155 | { | ||
156 | int x; | ||
157 | |||
158 | sc606_i2c_start(); | ||
159 | |||
160 | sc606_i2c_outb(SLAVE_ADDRESS); | ||
161 | x = sc606_i2c_getack(); | ||
162 | |||
163 | sc606_i2c_outb(reg); | ||
164 | x += sc606_i2c_getack(); | ||
165 | |||
166 | sc606_i2c_restart(); | ||
167 | |||
168 | sc606_i2c_outb(SLAVE_ADDRESS); | ||
169 | x += sc606_i2c_getack(); | ||
170 | |||
171 | sc606_i2c_outb(data); | ||
172 | x += sc606_i2c_getack(); | ||
173 | |||
174 | sc606_i2c_stop(); | ||
175 | |||
176 | return x; | ||
177 | } | ||
178 | |||
179 | |||
180 | |||
181 | int sc606_read(unsigned char reg, unsigned char* data) | ||
182 | { | ||
183 | int x; | ||
184 | |||
185 | sc606_i2c_start(); | ||
186 | sc606_i2c_outb(SLAVE_ADDRESS); | ||
187 | x = sc606_i2c_getack(); | ||
188 | |||
189 | sc606_i2c_outb(reg); | ||
190 | x += sc606_i2c_getack(); | ||
191 | |||
192 | sc606_i2c_restart(); | ||
193 | sc606_i2c_outb(SLAVE_ADDRESS | 1); | ||
194 | x += sc606_i2c_getack(); | ||
195 | |||
196 | *data = sc606_i2c_inb(); | ||
197 | sc606_i2c_stop(); | ||
198 | |||
199 | return x; | ||
200 | } | ||
201 | |||
202 | |||
203 | |||
204 | void sc606_init(void) | ||
205 | { | ||
206 | volatile int i; | ||
207 | |||
208 | /* Set GPB2 (EN) to 1 */ | ||
209 | GPBCON = (GPBCON & ~(3<<4)) | 1<<4; | ||
210 | |||
211 | /* Turn enable line on */ | ||
212 | GPBDAT |= 1<<2; | ||
213 | /* OFF GPBDAT &= ~(1 << 2); */ | ||
214 | |||
215 | /* About 400us - needs 350us */ | ||
216 | for (i = 200; i; i--) | ||
217 | { | ||
218 | DELAY_LO; | ||
219 | } | ||
220 | |||
221 | /* Set GPH9 (SDA) and GPH10 (SCL) to 1 */ | ||
222 | GPHUP &= ~(3<<9); | ||
223 | GPHCON = (GPHCON & ~(0xF<<18)) | 5<<18; | ||
224 | } | ||
225 | |||