diff options
Diffstat (limited to 'firmware/target/arm/imx31/mc13783-imx31.c')
-rw-r--r-- | firmware/target/arm/imx31/mc13783-imx31.c | 241 |
1 files changed, 173 insertions, 68 deletions
diff --git a/firmware/target/arm/imx31/mc13783-imx31.c b/firmware/target/arm/imx31/mc13783-imx31.c index a083614488..5146122327 100644 --- a/firmware/target/arm/imx31/mc13783-imx31.c +++ b/firmware/target/arm/imx31/mc13783-imx31.c | |||
@@ -20,7 +20,6 @@ | |||
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | #include "system.h" | 21 | #include "system.h" |
22 | #include "cpu.h" | 22 | #include "cpu.h" |
23 | #include "spi-imx31.h" | ||
24 | #include "gpio-imx31.h" | 23 | #include "gpio-imx31.h" |
25 | #include "mc13783.h" | 24 | #include "mc13783.h" |
26 | #include "debug.h" | 25 | #include "debug.h" |
@@ -29,9 +28,14 @@ | |||
29 | extern const struct mc13783_event_list mc13783_event_list; | 28 | extern const struct mc13783_event_list mc13783_event_list; |
30 | extern struct spi_node mc13783_spi; | 29 | extern struct spi_node mc13783_spi; |
31 | 30 | ||
31 | /* PMIC event service data */ | ||
32 | static int mc13783_thread_stack[DEFAULT_STACK_SIZE/sizeof(int)]; | 32 | static int mc13783_thread_stack[DEFAULT_STACK_SIZE/sizeof(int)]; |
33 | static const char *mc13783_thread_name = "pmic"; | 33 | static const char *mc13783_thread_name = "pmic"; |
34 | static struct wakeup mc13783_wake; | 34 | static struct wakeup mc13783_svc_wake; |
35 | |||
36 | /* Synchronous thread communication objects */ | ||
37 | static struct mutex mc13783_spi_mutex; | ||
38 | static struct wakeup mc13783_spi_wake; | ||
35 | 39 | ||
36 | /* Tracking for which interrupts are enabled */ | 40 | /* Tracking for which interrupts are enabled */ |
37 | static uint32_t pmic_int_enabled[2] = | 41 | static uint32_t pmic_int_enabled[2] = |
@@ -45,6 +49,34 @@ static const unsigned char pmic_ints_regs[2] = | |||
45 | 49 | ||
46 | static volatile unsigned int mc13783_thread_id = 0; | 50 | static volatile unsigned int mc13783_thread_id = 0; |
47 | 51 | ||
52 | static void mc13783_xfer_complete_cb(struct spi_transfer_desc *trans); | ||
53 | |||
54 | /* Transfer descriptor for synchronous reads and writes */ | ||
55 | static struct spi_transfer_desc mc13783_transfer = | ||
56 | { | ||
57 | .node = &mc13783_spi, | ||
58 | .txbuf = NULL, | ||
59 | .rxbuf = NULL, | ||
60 | .count = 0, | ||
61 | .callback = mc13783_xfer_complete_cb, | ||
62 | .next = NULL, | ||
63 | }; | ||
64 | |||
65 | /* Called when a transfer is finished and data is ready/written */ | ||
66 | static void mc13783_xfer_complete_cb(struct spi_transfer_desc *xfer) | ||
67 | { | ||
68 | if (xfer->count != 0) | ||
69 | return; | ||
70 | |||
71 | wakeup_signal(&mc13783_spi_wake); | ||
72 | } | ||
73 | |||
74 | static inline bool wait_for_transfer_complete(void) | ||
75 | { | ||
76 | return wakeup_wait(&mc13783_spi_wake, HZ*2) == OBJ_WAIT_SUCCEEDED && | ||
77 | mc13783_transfer.count == 0; | ||
78 | } | ||
79 | |||
48 | static void mc13783_interrupt_thread(void) | 80 | static void mc13783_interrupt_thread(void) |
49 | { | 81 | { |
50 | uint32_t pending[2]; | 82 | uint32_t pending[2]; |
@@ -56,18 +88,18 @@ static void mc13783_interrupt_thread(void) | |||
56 | { | 88 | { |
57 | const struct mc13783_event *event, *event_last; | 89 | const struct mc13783_event *event, *event_last; |
58 | 90 | ||
59 | wakeup_wait(&mc13783_wake, TIMEOUT_BLOCK); | 91 | wakeup_wait(&mc13783_svc_wake, TIMEOUT_BLOCK); |
60 | 92 | ||
61 | if (mc13783_thread_id == 0) | 93 | if (mc13783_thread_id == 0) |
62 | break; | 94 | break; |
63 | 95 | ||
64 | mc13783_read_regset(pmic_ints_regs, pending, 2); | 96 | mc13783_read_regs(pmic_ints_regs, pending, 2); |
65 | 97 | ||
66 | /* Only clear interrupts being dispatched */ | 98 | /* Only clear interrupts being dispatched */ |
67 | pending[0] &= pmic_int_enabled[0]; | 99 | pending[0] &= pmic_int_enabled[0]; |
68 | pending[1] &= pmic_int_enabled[1]; | 100 | pending[1] &= pmic_int_enabled[1]; |
69 | 101 | ||
70 | mc13783_write_regset(pmic_ints_regs, pending, 2); | 102 | mc13783_write_regs(pmic_ints_regs, pending, 2); |
71 | 103 | ||
72 | /* Whatever is going to be serviced in this loop has been | 104 | /* Whatever is going to be serviced in this loop has been |
73 | * acknowledged. Reenable interrupt and if anything was still | 105 | * acknowledged. Reenable interrupt and if anything was still |
@@ -93,7 +125,7 @@ static void mc13783_interrupt_thread(void) | |||
93 | } | 125 | } |
94 | 126 | ||
95 | if ((pending[0] | pending[1]) == 0) | 127 | if ((pending[0] | pending[1]) == 0) |
96 | break; /* Teminate early if nothing more to service */ | 128 | break; /* Terminate early if nothing more to service */ |
97 | } | 129 | } |
98 | while (++event < event_last); | 130 | while (++event < event_last); |
99 | } | 131 | } |
@@ -107,13 +139,16 @@ void mc13783_event(void) | |||
107 | /* Mask the interrupt (unmasked when PMIC thread services it). */ | 139 | /* Mask the interrupt (unmasked when PMIC thread services it). */ |
108 | imx31_regclr32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE); | 140 | imx31_regclr32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE); |
109 | MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE); | 141 | MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE); |
110 | wakeup_signal(&mc13783_wake); | 142 | wakeup_signal(&mc13783_svc_wake); |
111 | } | 143 | } |
112 | 144 | ||
113 | void mc13783_init(void) | 145 | void mc13783_init(void) |
114 | { | 146 | { |
115 | /* Serial interface must have been initialized first! */ | 147 | /* Serial interface must have been initialized first! */ |
116 | wakeup_init(&mc13783_wake); | 148 | wakeup_init(&mc13783_svc_wake); |
149 | mutex_init(&mc13783_spi_mutex); | ||
150 | |||
151 | wakeup_init(&mc13783_spi_wake); | ||
117 | 152 | ||
118 | /* Enable the PMIC SPI module */ | 153 | /* Enable the PMIC SPI module */ |
119 | spi_enable_module(&mc13783_spi); | 154 | spi_enable_module(&mc13783_spi); |
@@ -139,8 +174,9 @@ void mc13783_close(void) | |||
139 | return; | 174 | return; |
140 | 175 | ||
141 | mc13783_thread_id = 0; | 176 | mc13783_thread_id = 0; |
142 | wakeup_signal(&mc13783_wake); | 177 | wakeup_signal(&mc13783_svc_wake); |
143 | thread_wait(thread_id); | 178 | thread_wait(thread_id); |
179 | spi_disable_module(&mc13783_spi); | ||
144 | } | 180 | } |
145 | 181 | ||
146 | bool mc13783_enable_event(enum mc13783_event_ids id) | 182 | bool mc13783_enable_event(enum mc13783_event_ids id) |
@@ -150,12 +186,12 @@ bool mc13783_enable_event(enum mc13783_event_ids id) | |||
150 | int set = event->set; | 186 | int set = event->set; |
151 | uint32_t mask = event->mask; | 187 | uint32_t mask = event->mask; |
152 | 188 | ||
153 | spi_lock(&mc13783_spi); | 189 | mutex_lock(&mc13783_spi_mutex); |
154 | 190 | ||
155 | pmic_int_enabled[set] |= mask; | 191 | pmic_int_enabled[set] |= mask; |
156 | mc13783_clear(pmic_intm_regs[set], mask); | 192 | mc13783_clear(pmic_intm_regs[set], mask); |
157 | 193 | ||
158 | spi_unlock(&mc13783_spi); | 194 | mutex_unlock(&mc13783_spi_mutex); |
159 | 195 | ||
160 | return true; | 196 | return true; |
161 | } | 197 | } |
@@ -167,66 +203,77 @@ void mc13783_disable_event(enum mc13783_event_ids id) | |||
167 | int set = event->set; | 203 | int set = event->set; |
168 | uint32_t mask = event->mask; | 204 | uint32_t mask = event->mask; |
169 | 205 | ||
170 | spi_lock(&mc13783_spi); | 206 | mutex_lock(&mc13783_spi_mutex); |
171 | 207 | ||
172 | pmic_int_enabled[set] &= ~mask; | 208 | pmic_int_enabled[set] &= ~mask; |
173 | mc13783_set(pmic_intm_regs[set], mask); | 209 | mc13783_set(pmic_intm_regs[set], mask); |
174 | 210 | ||
175 | spi_unlock(&mc13783_spi); | 211 | mutex_unlock(&mc13783_spi_mutex); |
176 | } | 212 | } |
177 | 213 | ||
178 | uint32_t mc13783_set(unsigned address, uint32_t bits) | 214 | uint32_t mc13783_set(unsigned address, uint32_t bits) |
179 | { | 215 | { |
180 | spi_lock(&mc13783_spi); | 216 | uint32_t data; |
217 | |||
218 | mutex_lock(&mc13783_spi_mutex); | ||
181 | 219 | ||
182 | uint32_t data = mc13783_read(address); | 220 | data = mc13783_read(address); |
183 | 221 | ||
184 | if (data != MC13783_DATA_ERROR) | 222 | if (data != MC13783_DATA_ERROR) |
185 | mc13783_write(address, data | bits); | 223 | mc13783_write(address, data | bits); |
186 | 224 | ||
187 | spi_unlock(&mc13783_spi); | 225 | mutex_unlock(&mc13783_spi_mutex); |
188 | 226 | ||
189 | return data; | 227 | return data; |
190 | } | 228 | } |
191 | 229 | ||
192 | uint32_t mc13783_clear(unsigned address, uint32_t bits) | 230 | uint32_t mc13783_clear(unsigned address, uint32_t bits) |
193 | { | 231 | { |
194 | spi_lock(&mc13783_spi); | 232 | uint32_t data; |
195 | 233 | ||
196 | uint32_t data = mc13783_read(address); | 234 | mutex_lock(&mc13783_spi_mutex); |
235 | |||
236 | data = mc13783_read(address); | ||
197 | 237 | ||
198 | if (data != MC13783_DATA_ERROR) | 238 | if (data != MC13783_DATA_ERROR) |
199 | mc13783_write(address, data & ~bits); | 239 | mc13783_write(address, data & ~bits); |
200 | 240 | ||
201 | spi_unlock(&mc13783_spi); | 241 | mutex_unlock(&mc13783_spi_mutex); |
202 | 242 | ||
203 | return data; | 243 | return data; |
204 | } | 244 | } |
205 | 245 | ||
206 | int mc13783_write(unsigned address, uint32_t data) | 246 | int mc13783_write(unsigned address, uint32_t data) |
207 | { | 247 | { |
208 | struct spi_transfer xfer; | ||
209 | uint32_t packet; | 248 | uint32_t packet; |
249 | int i; | ||
210 | 250 | ||
211 | if (address >= MC13783_NUM_REGS) | 251 | if (address >= MC13783_NUM_REGS) |
212 | return -1; | 252 | return -1; |
213 | 253 | ||
214 | packet = (1 << 31) | (address << 25) | (data & 0xffffff); | 254 | packet = (1 << 31) | (address << 25) | (data & 0xffffff); |
215 | xfer.txbuf = &packet; | ||
216 | xfer.rxbuf = &packet; | ||
217 | xfer.count = 1; | ||
218 | 255 | ||
219 | if (!spi_transfer(&mc13783_spi, &xfer)) | 256 | mutex_lock(&mc13783_spi_mutex); |
220 | return -1; | 257 | |
258 | mc13783_transfer.txbuf = &packet; | ||
259 | mc13783_transfer.rxbuf = NULL; | ||
260 | mc13783_transfer.count = 1; | ||
261 | |||
262 | i = -1; | ||
263 | |||
264 | if (spi_transfer(&mc13783_transfer) && wait_for_transfer_complete()) | ||
265 | i = 1 - mc13783_transfer.count; | ||
266 | |||
267 | mutex_unlock(&mc13783_spi_mutex); | ||
221 | 268 | ||
222 | return 1 - xfer.count; | 269 | return i; |
223 | } | 270 | } |
224 | 271 | ||
225 | uint32_t mc13783_write_masked(unsigned address, uint32_t data, uint32_t mask) | 272 | uint32_t mc13783_write_masked(unsigned address, uint32_t data, uint32_t mask) |
226 | { | 273 | { |
227 | uint32_t old; | 274 | uint32_t old; |
228 | 275 | ||
229 | spi_lock(&mc13783_spi); | 276 | mutex_lock(&mc13783_spi_mutex); |
230 | 277 | ||
231 | old = mc13783_read(address); | 278 | old = mc13783_read(address); |
232 | 279 | ||
@@ -238,86 +285,144 @@ uint32_t mc13783_write_masked(unsigned address, uint32_t data, uint32_t mask) | |||
238 | old = MC13783_DATA_ERROR; | 285 | old = MC13783_DATA_ERROR; |
239 | } | 286 | } |
240 | 287 | ||
241 | spi_unlock(&mc13783_spi); | 288 | mutex_unlock(&mc13783_spi_mutex); |
242 | 289 | ||
243 | return old; | 290 | return old; |
244 | } | 291 | } |
245 | 292 | ||
246 | int mc13783_write_regset(const unsigned char *regs, const uint32_t *data, | 293 | uint32_t mc13783_read(unsigned address) |
247 | int count) | ||
248 | { | 294 | { |
249 | int i; | 295 | uint32_t packet; |
250 | struct spi_transfer xfer; | ||
251 | uint32_t packets[MC13783_NUM_REGS]; | ||
252 | 296 | ||
253 | if ((unsigned)count > MC13783_NUM_REGS) | 297 | if (address >= MC13783_NUM_REGS) |
254 | return -1; | 298 | return MC13783_DATA_ERROR; |
299 | |||
300 | packet = address << 25; | ||
301 | |||
302 | mutex_lock(&mc13783_spi_mutex); | ||
303 | |||
304 | mc13783_transfer.txbuf = &packet; | ||
305 | mc13783_transfer.rxbuf = &packet; | ||
306 | mc13783_transfer.count = 1; | ||
307 | |||
308 | if (!spi_transfer(&mc13783_transfer) || !wait_for_transfer_complete()) | ||
309 | packet = MC13783_DATA_ERROR; | ||
310 | |||
311 | mutex_unlock(&mc13783_spi_mutex); | ||
312 | |||
313 | return packet; | ||
314 | } | ||
315 | |||
316 | int mc13783_read_regs(const unsigned char *regs, uint32_t *buffer, | ||
317 | int count) | ||
318 | { | ||
319 | int i; | ||
255 | 320 | ||
256 | for (i = 0; i < count; i++) | 321 | for (i = 0; i < count; i++) |
257 | { | 322 | { |
258 | uint32_t reg = regs[i]; | 323 | unsigned reg = regs[i]; |
259 | 324 | ||
260 | if (reg >= MC13783_NUM_REGS) | 325 | if (reg >= MC13783_NUM_REGS) |
261 | return -1; | 326 | return -1; |
262 | 327 | ||
263 | packets[i] = (1 << 31) | (reg << 25) | (data[i] & 0xffffff); | 328 | buffer[i] = reg << 25; |
264 | } | 329 | } |
265 | 330 | ||
266 | xfer.txbuf = packets; | 331 | mutex_lock(&mc13783_spi_mutex); |
267 | xfer.rxbuf = packets; | ||
268 | xfer.count = count; | ||
269 | 332 | ||
270 | if (!spi_transfer(&mc13783_spi, &xfer)) | 333 | mc13783_transfer.txbuf = buffer; |
271 | return -1; | 334 | mc13783_transfer.rxbuf = buffer; |
335 | mc13783_transfer.count = count; | ||
336 | |||
337 | i = -1; | ||
338 | |||
339 | if (spi_transfer(&mc13783_transfer) && wait_for_transfer_complete()) | ||
340 | i = count - mc13783_transfer.count; | ||
272 | 341 | ||
273 | return count - xfer.count; | 342 | mutex_unlock(&mc13783_spi_mutex); |
343 | |||
344 | return i; | ||
274 | } | 345 | } |
275 | 346 | ||
276 | uint32_t mc13783_read(unsigned address) | 347 | int mc13783_write_regs(const unsigned char *regs, uint32_t *buffer, |
348 | int count) | ||
277 | { | 349 | { |
278 | uint32_t packet; | 350 | int i; |
279 | struct spi_transfer xfer; | ||
280 | 351 | ||
281 | if (address >= MC13783_NUM_REGS) | 352 | for (i = 0; i < count; i++) |
282 | return MC13783_DATA_ERROR; | 353 | { |
354 | unsigned reg = regs[i]; | ||
283 | 355 | ||
284 | packet = address << 25; | 356 | if (reg >= MC13783_NUM_REGS) |
357 | return -1; | ||
285 | 358 | ||
286 | xfer.txbuf = &packet; | 359 | buffer[i] = (1 << 31) | (reg << 25) | (buffer[i] & 0xffffff); |
287 | xfer.rxbuf = &packet; | 360 | } |
288 | xfer.count = 1; | ||
289 | 361 | ||
290 | if (!spi_transfer(&mc13783_spi, &xfer)) | 362 | mutex_lock(&mc13783_spi_mutex); |
291 | return MC13783_DATA_ERROR; | ||
292 | 363 | ||
293 | return packet; | 364 | mc13783_transfer.txbuf = buffer; |
365 | mc13783_transfer.rxbuf = NULL; | ||
366 | mc13783_transfer.count = count; | ||
367 | |||
368 | i = -1; | ||
369 | |||
370 | if (spi_transfer(&mc13783_transfer) && wait_for_transfer_complete()) | ||
371 | i = count - mc13783_transfer.count; | ||
372 | |||
373 | mutex_unlock(&mc13783_spi_mutex); | ||
374 | |||
375 | return i; | ||
294 | } | 376 | } |
295 | 377 | ||
296 | int mc13783_read_regset(const unsigned char *regs, uint32_t *buffer, | 378 | #if 0 /* Not needed right now */ |
297 | int count) | 379 | bool mc13783_read_async(struct spi_transfer_desc *xfer, |
380 | const unsigned char *regs, uint32_t *buffer, | ||
381 | int count, spi_transfer_cb_fn_type callback) | ||
298 | { | 382 | { |
299 | int i; | 383 | int i; |
300 | struct spi_transfer xfer; | ||
301 | |||
302 | if ((unsigned)count > MC13783_NUM_REGS) | ||
303 | return -1; | ||
304 | 384 | ||
305 | for (i = 0; i < count; i++) | 385 | for (i = 0; i < count; i++) |
306 | { | 386 | { |
307 | unsigned reg = regs[i]; | 387 | unsigned reg = regs[i]; |
308 | 388 | ||
309 | if (reg >= MC13783_NUM_REGS) | 389 | if (reg >= MC13783_NUM_REGS) |
310 | return -1; | 390 | return false; |
311 | 391 | ||
312 | buffer[i] = reg << 25; | 392 | buffer[i] = reg << 25; |
313 | } | 393 | } |
314 | 394 | ||
315 | xfer.txbuf = buffer; | 395 | xfer->node = &mc13783_spi; |
316 | xfer.rxbuf = buffer; | 396 | xfer->txbuf = buffer; |
317 | xfer.count = count; | 397 | xfer->rxbuf = buffer; |
398 | xfer->count = count; | ||
399 | xfer->callback = callback; | ||
318 | 400 | ||
319 | if (!spi_transfer(&mc13783_spi, &xfer)) | 401 | return spi_transfer(xfer); |
320 | return -1; | 402 | } |
403 | #endif | ||
404 | |||
405 | bool mc13783_write_async(struct spi_transfer_desc *xfer, | ||
406 | const unsigned char *regs, uint32_t *buffer, | ||
407 | int count, spi_transfer_cb_fn_type callback) | ||
408 | { | ||
409 | int i; | ||
410 | |||
411 | for (i = 0; i < count; i++) | ||
412 | { | ||
413 | unsigned reg = regs[i]; | ||
414 | |||
415 | if (reg >= MC13783_NUM_REGS) | ||
416 | return false; | ||
417 | |||
418 | buffer[i] = (1 << 31) | (reg << 25) | (buffer[i] & 0xffffff); | ||
419 | } | ||
420 | |||
421 | xfer->node = &mc13783_spi; | ||
422 | xfer->txbuf = buffer; | ||
423 | xfer->rxbuf = NULL; | ||
424 | xfer->count = count; | ||
425 | xfer->callback = callback; | ||
321 | 426 | ||
322 | return count - xfer.count; | 427 | return spi_transfer(xfer); |
323 | } | 428 | } |