summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Bukat <marcin.bukat@gmail.com>2012-08-27 23:18:31 +0200
committerMarcin Bukat <marcin.bukat@gmail.com>2012-08-27 23:18:31 +0200
commitae27c331e10fbdc4cb5516afce5eeb53eacb3962 (patch)
tree52aea83d39bab492c6aa95e967fc69f8b0e69301
parent16335da1cfc90fcf559f9d4ab6843708a3613d1c (diff)
downloadrockbox-ae27c331e10fbdc4cb5516afce5eeb53eacb3962.tar.gz
rockbox-ae27c331e10fbdc4cb5516afce5eeb53eacb3962.zip
rk27xx: Turn off i2c clock when not in use
Change-Id: Ifc6c25a53ace1a5f4d716a33d4979ea0a37fac98
-rw-r--r--firmware/target/arm/rk27xx/i2c-rk27xx.c309
1 files changed, 164 insertions, 145 deletions
diff --git a/firmware/target/arm/rk27xx/i2c-rk27xx.c b/firmware/target/arm/rk27xx/i2c-rk27xx.c
index 6fddde0f95..3535c68e42 100644
--- a/firmware/target/arm/rk27xx/i2c-rk27xx.c
+++ b/firmware/target/arm/rk27xx/i2c-rk27xx.c
@@ -40,7 +40,7 @@ static struct mutex i2c_mtx;
40 40
41static bool i2c_write_byte(uint8_t data, bool start) 41static bool i2c_write_byte(uint8_t data, bool start)
42{ 42{
43 long timeout = current_tick + 50; 43 long timeout = current_tick + HZ/50;
44 44
45 /* START */ 45 /* START */
46 I2C_CONR |= (1<<3) | (1<<2); /* master port enable, transmit bit */ 46 I2C_CONR |= (1<<3) | (1<<2); /* master port enable, transmit bit */
@@ -66,34 +66,34 @@ static bool i2c_write_byte(uint8_t data, bool start)
66 66
67static bool i2c_read_byte(unsigned char *data) 67static bool i2c_read_byte(unsigned char *data)
68{ 68{
69 long timeout = current_tick + HZ / 50; 69 long timeout = current_tick + HZ/50;
70 70
71 I2C_LCMR = (1<<2); /* resume op */ 71 I2C_LCMR = (1<<2); /* resume op */
72 72
73 while (!(I2C_ISR & (1<<1))) 73 while (!(I2C_ISR & (1<<1)))
74 if (TIME_AFTER(current_tick, timeout)) 74 if (TIME_AFTER(current_tick, timeout))
75 return false; 75 return false;
76 76
77 *data = I2C_MRXR; 77 *data = I2C_MRXR;
78 78
79 /* clear status bit */ 79 /* clear status bit */
80 I2C_ISR &= ~(1<<1); 80 I2C_ISR &= ~(1<<1);
81 81
82 return true; 82 return true;
83} 83}
84 84
85static bool i2c_stop(void) 85static bool i2c_stop(void)
86{ 86{
87 long timeout = current_tick + HZ / 50; 87 long timeout = current_tick + HZ/50;
88 88
89 I2C_CONR &= ~(1<<4); 89 I2C_CONR &= ~(1<<4);
90 I2C_LCMR |= (1<<2) | (1<<1); /* resume op, stop */ 90 I2C_LCMR |= (1<<2) | (1<<1); /* resume op, stop */
91 91
92 while (I2C_LCMR & (1<<1)) 92 while (I2C_LCMR & (1<<1))
93 if (TIME_AFTER(current_tick, timeout)) 93 if (TIME_AFTER(current_tick, timeout))
94 return false; 94 return false;
95 95
96 return true; 96 return true;
97} 97}
98 98
99/* route i2c bus to internal codec or external bus 99/* route i2c bus to internal codec or external bus
@@ -103,154 +103,173 @@ static bool i2c_stop(void)
103 */ 103 */
104static void i2c_iomux(unsigned char slave) 104static void i2c_iomux(unsigned char slave)
105{ 105{
106 unsigned long muxa = SCU_IOMUXA_CON & ~(0x1f<<14); 106 unsigned long muxa = SCU_IOMUXA_CON & ~(0x1f<<14);
107 107
108 if ((slave & 0xfe) == (0x27<<1)) 108 if ((slave & 0xfe) == (0x27<<1))
109 { 109 {
110 /* internal codec */ 110 /* internal codec */
111 SCU_IOMUXA_CON = (muxa | (1<<16) | (1<<14)); 111 SCU_IOMUXA_CON = (muxa | (1<<16) | (1<<14));
112 } 112 }
113 else 113 else
114 { 114 {
115 /* external I2C bus */ 115 /* external I2C bus */
116 SCU_IOMUXA_CON = (muxa | (1<<18)); 116 SCU_IOMUXA_CON = (muxa | (1<<18));
117 } 117 }
118} 118}
119 119
120void i2c_init(void) 120void i2c_init(void)
121{ 121{
122 mutex_init(&i2c_mtx); 122 mutex_init(&i2c_mtx);
123 123
124 SCU_CLKCFG &= ~(1<< 20);
125 124
126 I2C_OPR |= (1<<7); /* reset state machine */ 125 /* ungate i2c module clock */
127 sleep(HZ/100); 126 SCU_CLKCFG &= ~(1<< 20);
128 I2C_OPR &= ~((1<<7) | (1<<6)); /* clear ENABLE bit, deasert reset */
129 127
130 /* set I2C divider to stay within allowed SCL freq limit 128 I2C_OPR |= (1<<7); /* reset state machine */
131 * APBfreq = 50Mhz 129 sleep(HZ/100);
132 * SCLfreq = (APBfreq/5*(I2CCDVR[5:3] + 1) * 2^((I2CCDVR[2:0] + 1)) 130 I2C_OPR &= ~((1<<7) | (1<<6)); /* clear ENABLE bit, deasert reset */
133 */
134 131
135 /* we are driving this slightly above specs 132 /* set I2C divider to stay within allowed SCL freq limit
136 * (6<<3) | (1<<0) 416kHz 133 * APBfreq = 50Mhz
137 * (7<<3) | (1<<0) 357kHz 134 * SCLfreq = (APBfreq/5*(I2CCDVR[5:3] + 1) * 2^((I2CCDVR[2:0] + 1))
138 * (6<<3) | (2<<0) 208kHz 135 */
139 */
140 I2C_OPR = (I2C_OPR & ~(0x3F)) | (6<<3) | (1<<0);
141 136
142 I2C_IER = 0x00; 137 /* we are driving this slightly above specs
138 * (6<<3) | (1<<0) 416kHz
139 * (7<<3) | (1<<0) 357kHz
140 * (6<<3) | (2<<0) 208kHz
141 */
142 I2C_OPR = (I2C_OPR & ~(0x3F)) | (6<<3) | (1<<0);
143 143
144 I2C_OPR |= (1<<6); /* enable i2c core */ 144 I2C_IER = 0x00;
145
146 I2C_OPR |= (1<<6); /* enable i2c core */
147
148 /* turn off i2c module clock until we need to comunicate */
149 SCU_CLKCFG |= (1<< 20);
145} 150}
146 151
147int i2c_write(unsigned char slave, int address, int len, 152int i2c_write(unsigned char slave, int address, int len,
148 const unsigned char *data) 153 const unsigned char *data)
149{ 154{
150 mutex_lock(&i2c_mtx); 155 int ret = 0;
151
152 i2c_iomux(slave);
153
154 /* clear all flags */
155 I2C_ISR = 0x00;
156 I2C_IER = 0x00;
157
158 /* START */
159 if (! i2c_write_byte(slave & ~1, true))
160 {
161 mutex_unlock(&i2c_mtx);
162 return 1;
163 }
164
165 if (address >= 0)
166 {
167 if (! i2c_write_byte(address, false))
168 {
169 mutex_unlock(&i2c_mtx);
170 return 2;
171 }
172 }
173
174 /* write data */
175 while (len--)
176 {
177 if (! i2c_write_byte(*data++, false))
178 {
179 mutex_unlock(&i2c_mtx);
180 return 4;
181 }
182 }
183 156
184 /* STOP */ 157 mutex_lock(&i2c_mtx);
185 if (! i2c_stop()) 158
186 { 159 i2c_iomux(slave);
187 mutex_unlock(&i2c_mtx); 160
188 return 5; 161 /* ungate i2c clock */
189 } 162 SCU_CLKCFG &= ~(1<<20);
190 163
191 mutex_unlock(&i2c_mtx); 164 /* clear all flags */
192 return 0; 165 I2C_ISR = 0x00;
166 I2C_IER = 0x00;
167
168 /* START */
169 if (! i2c_write_byte(slave & ~1, true))
170 {
171 ret = 1;
172 goto end;
173 }
174
175 if (address >= 0)
176 {
177 if (! i2c_write_byte(address, false))
178 {
179 ret = 2;
180 goto end;
181 }
182 }
183
184 /* write data */
185 while (len--)
186 {
187 if (! i2c_write_byte(*data++, false))
188 {
189 ret = 4;
190 goto end;
191 }
192 }
193
194 /* STOP */
195 if (! i2c_stop())
196 {
197 ret = 5;
198 goto end;
199 }
200
201end:
202 mutex_unlock(&i2c_mtx);
203 SCU_CLKCFG |= (1<<20);
204 return ret;
193} 205}
194 206
195int i2c_read(unsigned char slave, int address, int len, unsigned char *data) 207int i2c_read(unsigned char slave, int address, int len, unsigned char *data)
196{ 208{
197 mutex_lock(&i2c_mtx); 209 int ret = 0;
198 210
199 i2c_iomux(slave); 211 mutex_lock(&i2c_mtx);
200 212
201 /* clear all flags */ 213 i2c_iomux(slave);
202 I2C_ISR = 0x00; 214
203 I2C_IER = 0x00; 215 /* ungate i2c module clock */
204 216 SCU_CLKCFG &= ~(1<<20);
205 if (address >= 0) 217
206 { 218 /* clear all flags */
207 /* START */ 219 I2C_ISR = 0x00;
208 if (! i2c_write_byte(slave & ~1, true)) 220 I2C_IER = 0x00;
209 { 221
210 mutex_unlock(&i2c_mtx); 222 if (address >= 0)
211 return 1; 223 {
212 } 224 /* START */
213 225 if (! i2c_write_byte(slave & ~1, true))
214 /* write address */ 226 {
215 if (! i2c_write_byte(address, false)) 227 ret = 1;
216 { 228 goto end;
217 mutex_unlock(&i2c_mtx); 229 }
218 return 2; 230
219 } 231 /* write address */
220 } 232 if (! i2c_write_byte(address, false))
221 233 {
222 /* (repeated) START */ 234 ret = 2;
223 if (! i2c_write_byte(slave | 1, true)) 235 goto end;
224 { 236 }
225 mutex_unlock(&i2c_mtx); 237 }
226 return 3; 238
227 } 239 /* (repeated) START */
228 240 if (! i2c_write_byte(slave | 1, true))
229 I2C_CONR &= ~(1<<3); /* clear transmit bit (switch to receive mode) */ 241 {
230 242 ret = 3;
231 while (len) 243 goto end;
232 { 244 }
233 if (! i2c_read_byte(data++)) 245
234 { 246 I2C_CONR &= ~(1<<3); /* clear transmit bit (switch to receive mode) */
235 mutex_unlock(&i2c_mtx); 247
236 return 4; 248 while (len)
237 } 249 {
238 250 if (! i2c_read_byte(data++))
239 if (len == 1) 251 {
240 I2C_CONR |= (1<<4); /* NACK */ 252 ret = 4;
241 else 253 goto end;
242 I2C_CONR &= ~(1<<4); /* ACK */ 254 }
243 255
244 len--; 256 if (len == 1)
245 } 257 I2C_CONR |= (1<<4); /* NACK */
258 else
259 I2C_CONR &= ~(1<<4); /* ACK */
260
261 len--;
262 }
246 263
247 /* STOP */ 264 /* STOP */
248 if (! i2c_stop()) 265 if (! i2c_stop())
249 { 266 {
250 mutex_unlock(&i2c_mtx); 267 ret = 5;
251 return 5; 268 goto end;
252 } 269 }
253 270
254 mutex_unlock(&i2c_mtx); 271end:
255 return 0; 272 mutex_unlock(&i2c_mtx);
273 SCU_CLKCFG |= (1<<20);
274 return ret;
256} 275}