summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx31/mc13783-imx31.c
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2011-12-18 10:41:43 +0000
committerMichael Sevakis <jethead71@rockbox.org>2011-12-18 10:41:43 +0000
commit292e7cab73c75260b7cfb7f90ad28938c8f1117a (patch)
tree4341681314958c3a9aa663e5ace52eb4b1e107ab /firmware/target/arm/imx31/mc13783-imx31.c
parent0efabb3d19e7690585641c4a19eca131d15b59d8 (diff)
downloadrockbox-292e7cab73c75260b7cfb7f90ad28938c8f1117a.tar.gz
rockbox-292e7cab73c75260b7cfb7f90ad28938c8f1117a.zip
Gigabeat S: PMIC SPI improvement and bugfixes.
Nick some aspects from the as3525 ascodec driver to improve throughput in the beast's SPI communications by switching tranfer descriptors to the caller's stack and getting rid of thread synchronization. Fix a bug that suddenly became obvious that could permanently stall the SPI driver because all data could be shifted out before the interrupt could get serviced. In that case, it needs a kick to restart it. Should probably put the SPI interrupt priority above DVFS. A tweak to the event registration interface to simplify it. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31353 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/imx31/mc13783-imx31.c')
-rw-r--r--firmware/target/arm/imx31/mc13783-imx31.c278
1 files changed, 106 insertions, 172 deletions
diff --git a/firmware/target/arm/imx31/mc13783-imx31.c b/firmware/target/arm/imx31/mc13783-imx31.c
index 094fbaa58b..268c33a549 100644
--- a/firmware/target/arm/imx31/mc13783-imx31.c
+++ b/firmware/target/arm/imx31/mc13783-imx31.c
@@ -34,10 +34,6 @@ static int mc13783_thread_stack[DEFAULT_STACK_SIZE/sizeof(int)];
34static const char * const mc13783_thread_name = "pmic"; 34static const char * const mc13783_thread_name = "pmic";
35static struct semaphore mc13783_svc_wake; 35static struct semaphore mc13783_svc_wake;
36 36
37/* Synchronous thread communication objects */
38static struct mutex mc13783_spi_mutex;
39static struct semaphore mc13783_spi_complete;
40
41/* Tracking for which interrupts are enabled */ 37/* Tracking for which interrupts are enabled */
42static uint32_t pmic_int_enabled[2] = 38static uint32_t pmic_int_enabled[2] =
43 { 0x00000000, 0x00000000 }; 39 { 0x00000000, 0x00000000 };
@@ -50,32 +46,27 @@ static const unsigned char pmic_ints_regs[2] =
50 46
51static volatile unsigned int mc13783_thread_id = 0; 47static volatile unsigned int mc13783_thread_id = 0;
52 48
53static void mc13783_xfer_complete_cb(struct spi_transfer_desc *trans); 49/* Extend the basic SPI transfer descriptor with our own fields */
54 50struct mc13783_transfer_desc
55/* Transfer descriptor for synchronous reads and writes */
56static struct spi_transfer_desc mc13783_transfer =
57{ 51{
58 .node = &mc13783_spi, 52 struct spi_transfer_desc xfer;
59 .txbuf = NULL, 53 union
60 .rxbuf = NULL, 54 {
61 .count = 0, 55 struct semaphore sema;
62 .callback = mc13783_xfer_complete_cb, 56 uint32_t data;
63 .next = NULL, 57 };
64}; 58};
65 59
66/* Called when a transfer is finished and data is ready/written */ 60/* Called when a transfer is finished and data is ready/written */
67static void mc13783_xfer_complete_cb(struct spi_transfer_desc *xfer) 61static void mc13783_xfer_complete_cb(struct spi_transfer_desc *xfer)
68{ 62{
69 if (xfer->count != 0) 63 semaphore_release(&((struct mc13783_transfer_desc *)xfer)->sema);
70 return;
71
72 semaphore_release(&mc13783_spi_complete);
73} 64}
74 65
75static inline bool wait_for_transfer_complete(void) 66static inline bool wait_for_transfer_complete(struct mc13783_transfer_desc *xfer)
76{ 67{
77 return semaphore_wait(&mc13783_spi_complete, HZ*2) 68 return semaphore_wait(&xfer->sema, TIMEOUT_BLOCK)
78 == OBJ_WAIT_SUCCEEDED && mc13783_transfer.count == 0; 69 == OBJ_WAIT_SUCCEEDED && xfer->xfer.count == 0;
79} 70}
80 71
81static void mc13783_interrupt_thread(void) 72static void mc13783_interrupt_thread(void)
@@ -114,15 +105,14 @@ static void mc13783_interrupt_thread(void)
114 /* .count is surely expected to be > 0 */ 105 /* .count is surely expected to be > 0 */
115 do 106 do
116 { 107 {
117 enum mc13783_event_sets set = event->set; 108 unsigned int set = event->int_id / MC13783_INT_ID_SET_DIV;
118 uint32_t pnd = pending[set]; 109 uint32_t pnd = pending[set];
119 uint32_t mask = event->mask; 110 uint32_t mask = 1 << (event->int_id & MC13783_INT_ID_NUM_MASK);
120 111
121 if (pnd & mask) 112 if (pnd & mask)
122 { 113 {
123 event->callback(); 114 event->callback();
124 pnd &= ~mask; 115 pending[set] = pnd & ~mask;
125 pending[set] = pnd;
126 } 116 }
127 117
128 if ((pending[0] | pending[1]) == 0) 118 if ((pending[0] | pending[1]) == 0)
@@ -147,9 +137,6 @@ void INIT_ATTR mc13783_init(void)
147{ 137{
148 /* Serial interface must have been initialized first! */ 138 /* Serial interface must have been initialized first! */
149 semaphore_init(&mc13783_svc_wake, 1, 0); 139 semaphore_init(&mc13783_svc_wake, 1, 0);
150 mutex_init(&mc13783_spi_mutex);
151
152 semaphore_init(&mc13783_spi_complete, 1, 0);
153 140
154 /* Enable the PMIC SPI module */ 141 /* Enable the PMIC SPI module */
155 spi_enable_module(&mc13783_spi); 142 spi_enable_module(&mc13783_spi);
@@ -183,205 +170,169 @@ void mc13783_close(void)
183bool mc13783_enable_event(enum mc13783_event_ids id) 170bool mc13783_enable_event(enum mc13783_event_ids id)
184{ 171{
185 const struct mc13783_event * const event = &mc13783_events[id]; 172 const struct mc13783_event * const event = &mc13783_events[id];
186 int set = event->set; 173 unsigned int set = event->int_id / MC13783_INT_ID_SET_DIV;
187 uint32_t mask = event->mask; 174 uint32_t mask = 1 << (event->int_id & MC13783_INT_ID_NUM_MASK);
188
189 mutex_lock(&mc13783_spi_mutex);
190 175
191 pmic_int_enabled[set] |= mask; 176 pmic_int_enabled[set] |= mask;
192 mc13783_clear(pmic_intm_regs[set], mask); 177 mc13783_clear(pmic_intm_regs[set], mask);
193 178
194 mutex_unlock(&mc13783_spi_mutex);
195
196 return true; 179 return true;
197} 180}
198 181
199void mc13783_disable_event(enum mc13783_event_ids id) 182void mc13783_disable_event(enum mc13783_event_ids id)
200{ 183{
201 const struct mc13783_event * const event = &mc13783_events[id]; 184 const struct mc13783_event * const event = &mc13783_events[id];
202 int set = event->set; 185 unsigned int set = event->int_id / MC13783_INT_ID_SET_DIV;
203 uint32_t mask = event->mask; 186 uint32_t mask = 1 << (event->int_id & MC13783_INT_ID_NUM_MASK);
204
205 mutex_lock(&mc13783_spi_mutex);
206 187
207 pmic_int_enabled[set] &= ~mask; 188 pmic_int_enabled[set] &= ~mask;
208 mc13783_set(pmic_intm_regs[set], mask); 189 mc13783_set(pmic_intm_regs[set], mask);
209
210 mutex_unlock(&mc13783_spi_mutex);
211} 190}
212 191
213uint32_t mc13783_set(unsigned address, uint32_t bits) 192static inline bool mc13783_transfer(struct spi_transfer_desc *xfer,
193 uint32_t *txbuf,
194 uint32_t *rxbuf,
195 int count,
196 spi_transfer_cb_fn_type callback)
214{ 197{
215 uint32_t data; 198 xfer->node = &mc13783_spi;
216 199 xfer->txbuf = txbuf;
217 mutex_lock(&mc13783_spi_mutex); 200 xfer->rxbuf = rxbuf;
218 201 xfer->count = count;
219 data = mc13783_read(address); 202 xfer->callback = callback;
220 203 xfer->next = NULL;
221 if (data != MC13783_DATA_ERROR)
222 mc13783_write(address, data | bits);
223 204
224 mutex_unlock(&mc13783_spi_mutex); 205 return spi_transfer(xfer);
206}
225 207
226 return data; 208uint32_t mc13783_set(unsigned address, uint32_t bits)
209{
210 return mc13783_write_masked(address, bits, bits);
227} 211}
228 212
229uint32_t mc13783_clear(unsigned address, uint32_t bits) 213uint32_t mc13783_clear(unsigned address, uint32_t bits)
230{ 214{
231 uint32_t data; 215 return mc13783_write_masked(address, 0, bits);
232
233 mutex_lock(&mc13783_spi_mutex);
234
235 data = mc13783_read(address);
236
237 if (data != MC13783_DATA_ERROR)
238 mc13783_write(address, data & ~bits);
239
240 mutex_unlock(&mc13783_spi_mutex);
241
242 return data;
243} 216}
244 217
245int mc13783_write(unsigned address, uint32_t data) 218/* Called when the first transfer of mc13783_write_masked is complete */
219static void mc13783_write_masked_cb(struct spi_transfer_desc *xfer)
246{ 220{
247 uint32_t packet; 221 struct mc13783_transfer_desc *desc = (struct mc13783_transfer_desc *)xfer;
248 int i; 222 uint32_t *packets = desc->xfer.rxbuf; /* Will have been advanced by 1 */
223 packets[0] |= packets[-1] & ~desc->data;
224}
249 225
226uint32_t mc13783_write_masked(unsigned address, uint32_t data, uint32_t mask)
227{
250 if (address >= MC13783_NUM_REGS) 228 if (address >= MC13783_NUM_REGS)
251 return -1; 229 return MC13783_DATA_ERROR;
230
231 mask &= 0xffffff;
252 232
253 packet = (1 << 31) | (address << 25) | (data & 0xffffff); 233 uint32_t packets[2] =
234 {
235 address << 25,
236 (1 << 31) | (address << 25) | (data & mask)
237 };
254 238
255 mutex_lock(&mc13783_spi_mutex); 239 struct mc13783_transfer_desc xfers[2];
240 xfers[0].data = mask;
241 semaphore_init(&xfers[1].sema, 1, 0);
256 242
257 mc13783_transfer.txbuf = &packet; 243 unsigned long cpsr = disable_irq_save();
258 mc13783_transfer.rxbuf = NULL;
259 mc13783_transfer.count = 1;
260 244
261 i = -1; 245 /* Queue up two transfers in a row */
246 bool ok = mc13783_transfer(&xfers[0].xfer, &packets[0], &packets[0], 1,
247 mc13783_write_masked_cb) &&
248 mc13783_transfer(&xfers[1].xfer, &packets[1], NULL, 1,
249 mc13783_xfer_complete_cb);
262 250
263 if (spi_transfer(&mc13783_transfer) && wait_for_transfer_complete()) 251 restore_irq(cpsr);
264 i = 1 - mc13783_transfer.count;
265 252
266 mutex_unlock(&mc13783_spi_mutex); 253 if (ok && wait_for_transfer_complete(&xfers[1]))
254 return packets[0];
267 255
268 return i; 256 return MC13783_DATA_ERROR;
269} 257}
270 258
271uint32_t mc13783_write_masked(unsigned address, uint32_t data, uint32_t mask) 259uint32_t mc13783_read(unsigned address)
272{ 260{
273 uint32_t old; 261 if (address >= MC13783_NUM_REGS)
262 return MC13783_DATA_ERROR;
274 263
275 mutex_lock(&mc13783_spi_mutex); 264 uint32_t packet = address << 25;
276 265
277 old = mc13783_read(address); 266 struct mc13783_transfer_desc xfer;
267 semaphore_init(&xfer.sema, 1, 0);
278 268
279 if (old != MC13783_DATA_ERROR) 269 if (mc13783_transfer(&xfer.xfer, &packet, &packet, 1,
270 mc13783_xfer_complete_cb) &&
271 wait_for_transfer_complete(&xfer))
280 { 272 {
281 data = (old & ~mask) | (data & mask); 273 return packet;
282
283 if (mc13783_write(address, data) != 1)
284 old = MC13783_DATA_ERROR;
285 } 274 }
286 275
287 mutex_unlock(&mc13783_spi_mutex); 276 return MC13783_DATA_ERROR;
288
289 return old;
290} 277}
291 278
292uint32_t mc13783_read(unsigned address) 279int mc13783_write(unsigned address, uint32_t data)
293{ 280{
294 uint32_t packet;
295
296 if (address >= MC13783_NUM_REGS) 281 if (address >= MC13783_NUM_REGS)
297 return MC13783_DATA_ERROR; 282 return -1;
298
299 packet = address << 25;
300
301 mutex_lock(&mc13783_spi_mutex);
302 283
303 mc13783_transfer.txbuf = &packet; 284 uint32_t packet = (1 << 31) | (address << 25) | (data & 0xffffff);
304 mc13783_transfer.rxbuf = &packet;
305 mc13783_transfer.count = 1;
306 285
307 if (!spi_transfer(&mc13783_transfer) || !wait_for_transfer_complete()) 286 struct mc13783_transfer_desc xfer;
308 packet = MC13783_DATA_ERROR; 287 semaphore_init(&xfer.sema, 1, 0);
309 288
310 mutex_unlock(&mc13783_spi_mutex); 289 if (mc13783_transfer(&xfer.xfer, &packet, NULL, 1,
290 mc13783_xfer_complete_cb) &&
291 wait_for_transfer_complete(&xfer))
292 {
293 return 1 - xfer.xfer.count;
294 }
311 295
312 return packet; 296 return -1;
313} 297}
314 298
315int mc13783_read_regs(const unsigned char *regs, uint32_t *buffer, 299int mc13783_read_regs(const unsigned char *regs, uint32_t *buffer,
316 int count) 300 int count)
317{ 301{
318 int i; 302 struct mc13783_transfer_desc xfer;
303 semaphore_init(&xfer.sema, 1, 0);
319 304
320 for (i = 0; i < count; i++) 305 if (mc13783_read_async(&xfer.xfer, regs, buffer, count,
306 mc13783_xfer_complete_cb) &&
307 wait_for_transfer_complete(&xfer))
321 { 308 {
322 unsigned reg = regs[i]; 309 return count - xfer.xfer.count;
323
324 if (reg >= MC13783_NUM_REGS)
325 return -1;
326
327 buffer[i] = reg << 25;
328 } 310 }
329 311
330 mutex_lock(&mc13783_spi_mutex); 312 return -1;
331
332 mc13783_transfer.txbuf = buffer;
333 mc13783_transfer.rxbuf = buffer;
334 mc13783_transfer.count = count;
335
336 i = -1;
337
338 if (spi_transfer(&mc13783_transfer) && wait_for_transfer_complete())
339 i = count - mc13783_transfer.count;
340
341 mutex_unlock(&mc13783_spi_mutex);
342
343 return i;
344} 313}
345 314
346int mc13783_write_regs(const unsigned char *regs, uint32_t *buffer, 315int mc13783_write_regs(const unsigned char *regs, uint32_t *buffer,
347 int count) 316 int count)
348{ 317{
349 int i; 318 struct mc13783_transfer_desc xfer;
319 semaphore_init(&xfer.sema, 1, 0);
350 320
351 for (i = 0; i < count; i++) 321 if (mc13783_write_async(&xfer.xfer, regs, buffer, count,
322 mc13783_xfer_complete_cb) &&
323 wait_for_transfer_complete(&xfer))
352 { 324 {
353 unsigned reg = regs[i]; 325 return count - xfer.xfer.count;
354
355 if (reg >= MC13783_NUM_REGS)
356 return -1;
357
358 buffer[i] = (1 << 31) | (reg << 25) | (buffer[i] & 0xffffff);
359 } 326 }
360 327
361 mutex_lock(&mc13783_spi_mutex); 328 return -1;
362
363 mc13783_transfer.txbuf = buffer;
364 mc13783_transfer.rxbuf = NULL;
365 mc13783_transfer.count = count;
366
367 i = -1;
368
369 if (spi_transfer(&mc13783_transfer) && wait_for_transfer_complete())
370 i = count - mc13783_transfer.count;
371
372 mutex_unlock(&mc13783_spi_mutex);
373
374 return i;
375} 329}
376 330
377#if 0 /* Not needed right now */
378bool mc13783_read_async(struct spi_transfer_desc *xfer, 331bool mc13783_read_async(struct spi_transfer_desc *xfer,
379 const unsigned char *regs, uint32_t *buffer, 332 const unsigned char *regs, uint32_t *buffer,
380 int count, spi_transfer_cb_fn_type callback) 333 int count, spi_transfer_cb_fn_type callback)
381{ 334{
382 int i; 335 for (int i = 0; i < count; i++)
383
384 for (i = 0; i < count; i++)
385 { 336 {
386 unsigned reg = regs[i]; 337 unsigned reg = regs[i];
387 338
@@ -391,24 +342,14 @@ bool mc13783_read_async(struct spi_transfer_desc *xfer,
391 buffer[i] = reg << 25; 342 buffer[i] = reg << 25;
392 } 343 }
393 344
394 xfer->node = &mc13783_spi; 345 return mc13783_transfer(xfer, buffer, buffer, count, callback);
395 xfer->txbuf = buffer;
396 xfer->rxbuf = buffer;
397 xfer->count = count;
398 xfer->callback = callback;
399 xfer->next = NULL;
400
401 return spi_transfer(xfer);
402} 346}
403#endif
404 347
405bool mc13783_write_async(struct spi_transfer_desc *xfer, 348bool mc13783_write_async(struct spi_transfer_desc *xfer,
406 const unsigned char *regs, uint32_t *buffer, 349 const unsigned char *regs, uint32_t *buffer,
407 int count, spi_transfer_cb_fn_type callback) 350 int count, spi_transfer_cb_fn_type callback)
408{ 351{
409 int i; 352 for (int i = 0; i < count; i++)
410
411 for (i = 0; i < count; i++)
412 { 353 {
413 unsigned reg = regs[i]; 354 unsigned reg = regs[i];
414 355
@@ -418,12 +359,5 @@ bool mc13783_write_async(struct spi_transfer_desc *xfer,
418 buffer[i] = (1 << 31) | (reg << 25) | (buffer[i] & 0xffffff); 359 buffer[i] = (1 << 31) | (reg << 25) | (buffer[i] & 0xffffff);
419 } 360 }
420 361
421 xfer->node = &mc13783_spi; 362 return mc13783_transfer(xfer, buffer, NULL, count, callback);
422 xfer->txbuf = buffer;
423 xfer->rxbuf = NULL;
424 xfer->count = count;
425 xfer->callback = callback;
426 xfer->next = NULL;
427
428 return spi_transfer(xfer);
429} 363}