summaryrefslogtreecommitdiff
path: root/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c
diff options
context:
space:
mode:
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.c225
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
38static void sc606_i2c_start(void)
39{
40 SCL_SDA_HI;
41 DELAY;
42 SDA_LO;
43 DELAY;
44 SCL_LO;
45}
46
47static void sc606_i2c_restart(void)
48{
49 SCL_SDA_HI;
50 DELAY;
51 SDA_LO;
52 DELAY;
53 SCL_LO;
54}
55
56static void sc606_i2c_stop(void)
57{
58 SDA_LO;
59 SCL_HI;
60 DELAY_HI;
61 SDA_HI;
62}
63
64static void sc606_i2c_ack(void)
65{
66
67 SDA_LO;
68 SCL_HI;
69 DELAY_HI;
70 SCL_LO;
71}
72
73
74
75static 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
99static 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
129static 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 */
154int 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
181int 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
204void 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