summaryrefslogtreecommitdiff
path: root/firmware/target
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target')
-rw-r--r--firmware/target/arm/as3525/ascodec-as3525.c42
1 files changed, 25 insertions, 17 deletions
diff --git a/firmware/target/arm/as3525/ascodec-as3525.c b/firmware/target/arm/as3525/ascodec-as3525.c
index be81178859..634648afe4 100644
--- a/firmware/target/arm/as3525/ascodec-as3525.c
+++ b/firmware/target/arm/as3525/ascodec-as3525.c
@@ -159,21 +159,12 @@ static void ascodec_finish_req(struct ascodec_request *req)
159 */ 159 */
160 while (i2c_busy()); 160 while (i2c_busy());
161 161
162 /* disable clock */
163 bitclr32(&CGU_PERI, CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE);
164
165 req->status = 1; 162 req->status = 1;
166 163
167 if (req->callback) { 164 if (req->callback) {
168 req->callback(req->data, req_data_ptr - req->data); 165 req->callback(req->data, req_data_ptr - req->data);
169 } 166 }
170 semaphore_release(&req->complete); 167 semaphore_release(&req->complete);
171
172 req_head = req->next;
173 req->next = NULL;
174 if (req_head == NULL)
175 req_tail = NULL;
176
177} 168}
178 169
179static int ascodec_continue_req(struct ascodec_request *req, int irq_status) 170static int ascodec_continue_req(struct ascodec_request *req, int irq_status)
@@ -226,13 +217,12 @@ static void ascodec_start_req(struct ascodec_request *req)
226 217
227void INT_I2C_AUDIO(void) 218void INT_I2C_AUDIO(void)
228{ 219{
229 int irq_status = I2C2_MIS; 220 struct ascodec_request *req = req_head;
230 int status = REQ_FINISHED;
231 221
232 if (req_head != NULL) 222 int irq_status = I2C2_MIS;
233 status = ascodec_continue_req(req_head, irq_status); 223 int status = ascodec_continue_req(req, irq_status);
234 224
235 I2C2_INT_CLR |= irq_status; /* clear interrupt status */ 225 I2C2_INT_CLR = irq_status; /* clear interrupt status */
236 226
237 if (status != REQ_UNFINISHED) { 227 if (status != REQ_UNFINISHED) {
238 /* mask rx/tx interrupts */ 228 /* mask rx/tx interrupts */
@@ -240,15 +230,31 @@ void INT_I2C_AUDIO(void)
240 I2C2_IRQ_RXOVER|I2C2_IRQ_ACKTIMEO); 230 I2C2_IRQ_RXOVER|I2C2_IRQ_ACKTIMEO);
241 231
242 if (status == REQ_FINISHED) 232 if (status == REQ_FINISHED)
243 ascodec_finish_req(req_head); 233 ascodec_finish_req(req);
234
235 int oldlevel = disable_irq_save(); /* IRQs are stacked */
244 236
245 /* 237 /*
246 * If status == REQ_RETRY, this will restart 238 * If status == REQ_RETRY, this will restart
247 * the request because we didn't remove it from 239 * the request because we didn't remove it from
248 * the request list 240 * the request list
249 */ 241 */
250 if (req_head) 242
243 if (status == REQ_FINISHED) {
244 req_head = req->next;
245 req->next = NULL;
246 }
247
248 if (req_head == NULL) {
249 req_tail = NULL;
250
251 /* disable clock */
252 bitclr32(&CGU_PERI, CGU_I2C_AUDIO_MASTER_CLOCK_ENABLE);
253 } else {
251 ascodec_start_req(req_head); 254 ascodec_start_req(req_head);
255 }
256
257 restore_irq(oldlevel);
252 } 258 }
253} 259}
254 260
@@ -278,7 +284,7 @@ void ascodec_init(void)
278 I2C2_CNTRL = I2C2_CNTRL_DEFAULT; 284 I2C2_CNTRL = I2C2_CNTRL_DEFAULT;
279 285
280 I2C2_IMR = 0x00; /* disable interrupts */ 286 I2C2_IMR = 0x00; /* disable interrupts */
281 I2C2_INT_CLR |= I2C2_RIS; /* clear interrupt status */ 287 I2C2_INT_CLR = I2C2_RIS; /* clear interrupt status */
282 VIC_INT_ENABLE = INTERRUPT_I2C_AUDIO; 288 VIC_INT_ENABLE = INTERRUPT_I2C_AUDIO;
283 VIC_INT_ENABLE = INTERRUPT_AUDIO; 289 VIC_INT_ENABLE = INTERRUPT_AUDIO;
284 290
@@ -338,6 +344,8 @@ static void ascodec_submit(struct ascodec_request *req)
338 344
339static void ascodec_wait(struct ascodec_request *req) 345static void ascodec_wait(struct ascodec_request *req)
340{ 346{
347 /* NOTE: Only safe from thread context */
348
341 if (irq_enabled()) { 349 if (irq_enabled()) {
342 semaphore_wait(&req->complete, TIMEOUT_BLOCK); 350 semaphore_wait(&req->complete, TIMEOUT_BLOCK);
343 return; 351 return;