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.c201
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
38static void sc606_i2c_start(void) 55static 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
47static void sc606_i2c_restart(void)
48{
49 SCL_SDA_HI;
50 DELAY;
51 SDA_LO;
52 DELAY;
53 SCL_LO;
54} 63}
55 64
56static void sc606_i2c_stop(void) 65static 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
64static void sc606_i2c_ack(void) 73static 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 82static bool sc606_i2c_getack(void)
74
75static 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
99static void sc606_i2c_outb(unsigned char byte) 98static 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
129static unsigned char sc606_i2c_inb(void) 116static 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 */
154int sc606_write(unsigned char reg, unsigned char data) 138int 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
181int sc606_read(unsigned char reg, unsigned char* data) 163int 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
204void sc606_init(void) 184void 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