diff options
author | Marcin Bukat <marcin.bukat@gmail.com> | 2012-08-27 23:18:31 +0200 |
---|---|---|
committer | Marcin Bukat <marcin.bukat@gmail.com> | 2012-08-27 23:18:31 +0200 |
commit | ae27c331e10fbdc4cb5516afce5eeb53eacb3962 (patch) | |
tree | 52aea83d39bab492c6aa95e967fc69f8b0e69301 | |
parent | 16335da1cfc90fcf559f9d4ab6843708a3613d1c (diff) | |
download | rockbox-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.c | 309 |
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 | ||
41 | static bool i2c_write_byte(uint8_t data, bool start) | 41 | static 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 | ||
67 | static bool i2c_read_byte(unsigned char *data) | 67 | static 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 | ||
85 | static bool i2c_stop(void) | 85 | static 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 | */ |
104 | static void i2c_iomux(unsigned char slave) | 104 | static 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 | ||
120 | void i2c_init(void) | 120 | void 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 | ||
147 | int i2c_write(unsigned char slave, int address, int len, | 152 | int 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 | |||
201 | end: | ||
202 | mutex_unlock(&i2c_mtx); | ||
203 | SCU_CLKCFG |= (1<<20); | ||
204 | return ret; | ||
193 | } | 205 | } |
194 | 206 | ||
195 | int i2c_read(unsigned char slave, int address, int len, unsigned char *data) | 207 | int 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); | 271 | end: |
255 | return 0; | 272 | mutex_unlock(&i2c_mtx); |
273 | SCU_CLKCFG |= (1<<20); | ||
274 | return ret; | ||
256 | } | 275 | } |