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 @@ ****************************************************************************/ #include "system.h" #include "cpu.h" -#include "spi-imx31.h" #include "gpio-imx31.h" #include "mc13783.h" #include "debug.h" @@ -29,9 +28,14 @@ extern const struct mc13783_event_list mc13783_event_list; extern struct spi_node mc13783_spi; +/* PMIC event service data */ static int mc13783_thread_stack[DEFAULT_STACK_SIZE/sizeof(int)]; static const char *mc13783_thread_name = "pmic"; -static struct wakeup mc13783_wake; +static struct wakeup mc13783_svc_wake; + +/* Synchronous thread communication objects */ +static struct mutex mc13783_spi_mutex; +static struct wakeup mc13783_spi_wake; /* Tracking for which interrupts are enabled */ static uint32_t pmic_int_enabled[2] = @@ -45,6 +49,34 @@ static const unsigned char pmic_ints_regs[2] = static volatile unsigned int mc13783_thread_id = 0; +static void mc13783_xfer_complete_cb(struct spi_transfer_desc *trans); + +/* Transfer descriptor for synchronous reads and writes */ +static struct spi_transfer_desc mc13783_transfer = +{ + .node = &mc13783_spi, + .txbuf = NULL, + .rxbuf = NULL, + .count = 0, + .callback = mc13783_xfer_complete_cb, + .next = NULL, +}; + +/* Called when a transfer is finished and data is ready/written */ +static void mc13783_xfer_complete_cb(struct spi_transfer_desc *xfer) +{ + if (xfer->count != 0) + return; + + wakeup_signal(&mc13783_spi_wake); +} + +static inline bool wait_for_transfer_complete(void) +{ + return wakeup_wait(&mc13783_spi_wake, HZ*2) == OBJ_WAIT_SUCCEEDED && + mc13783_transfer.count == 0; +} + static void mc13783_interrupt_thread(void) { uint32_t pending[2]; @@ -56,18 +88,18 @@ static void mc13783_interrupt_thread(void) { const struct mc13783_event *event, *event_last; - wakeup_wait(&mc13783_wake, TIMEOUT_BLOCK); + wakeup_wait(&mc13783_svc_wake, TIMEOUT_BLOCK); if (mc13783_thread_id == 0) break; - mc13783_read_regset(pmic_ints_regs, pending, 2); + mc13783_read_regs(pmic_ints_regs, pending, 2); /* Only clear interrupts being dispatched */ pending[0] &= pmic_int_enabled[0]; pending[1] &= pmic_int_enabled[1]; - mc13783_write_regset(pmic_ints_regs, pending, 2); + mc13783_write_regs(pmic_ints_regs, pending, 2); /* Whatever is going to be serviced in this loop has been * acknowledged. Reenable interrupt and if anything was still @@ -93,7 +125,7 @@ static void mc13783_interrupt_thread(void) } if ((pending[0] | pending[1]) == 0) - break; /* Teminate early if nothing more to service */ + break; /* Terminate early if nothing more to service */ } while (++event < event_last); } @@ -107,13 +139,16 @@ void mc13783_event(void) /* Mask the interrupt (unmasked when PMIC thread services it). */ imx31_regclr32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE); MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE); - wakeup_signal(&mc13783_wake); + wakeup_signal(&mc13783_svc_wake); } void mc13783_init(void) { /* Serial interface must have been initialized first! */ - wakeup_init(&mc13783_wake); + wakeup_init(&mc13783_svc_wake); + mutex_init(&mc13783_spi_mutex); + + wakeup_init(&mc13783_spi_wake); /* Enable the PMIC SPI module */ spi_enable_module(&mc13783_spi); @@ -139,8 +174,9 @@ void mc13783_close(void) return; mc13783_thread_id = 0; - wakeup_signal(&mc13783_wake); + wakeup_signal(&mc13783_svc_wake); thread_wait(thread_id); + spi_disable_module(&mc13783_spi); } bool mc13783_enable_event(enum mc13783_event_ids id) @@ -150,12 +186,12 @@ bool mc13783_enable_event(enum mc13783_event_ids id) int set = event->set; uint32_t mask = event->mask; - spi_lock(&mc13783_spi); + mutex_lock(&mc13783_spi_mutex); pmic_int_enabled[set] |= mask; mc13783_clear(pmic_intm_regs[set], mask); - spi_unlock(&mc13783_spi); + mutex_unlock(&mc13783_spi_mutex); return true; } @@ -167,66 +203,77 @@ void mc13783_disable_event(enum mc13783_event_ids id) int set = event->set; uint32_t mask = event->mask; - spi_lock(&mc13783_spi); + mutex_lock(&mc13783_spi_mutex); pmic_int_enabled[set] &= ~mask; mc13783_set(pmic_intm_regs[set], mask); - spi_unlock(&mc13783_spi); + mutex_unlock(&mc13783_spi_mutex); } uint32_t mc13783_set(unsigned address, uint32_t bits) { - spi_lock(&mc13783_spi); + uint32_t data; + + mutex_lock(&mc13783_spi_mutex); - uint32_t data = mc13783_read(address); + data = mc13783_read(address); if (data != MC13783_DATA_ERROR) mc13783_write(address, data | bits); - spi_unlock(&mc13783_spi); + mutex_unlock(&mc13783_spi_mutex); return data; } uint32_t mc13783_clear(unsigned address, uint32_t bits) { - spi_lock(&mc13783_spi); + uint32_t data; - uint32_t data = mc13783_read(address); + mutex_lock(&mc13783_spi_mutex); + + data = mc13783_read(address); if (data != MC13783_DATA_ERROR) mc13783_write(address, data & ~bits); - spi_unlock(&mc13783_spi); + mutex_unlock(&mc13783_spi_mutex); return data; } int mc13783_write(unsigned address, uint32_t data) { - struct spi_transfer xfer; uint32_t packet; + int i; if (address >= MC13783_NUM_REGS) return -1; packet = (1 << 31) | (address << 25) | (data & 0xffffff); - xfer.txbuf = &packet; - xfer.rxbuf = &packet; - xfer.count = 1; - if (!spi_transfer(&mc13783_spi, &xfer)) - return -1; + mutex_lock(&mc13783_spi_mutex); + + mc13783_transfer.txbuf = &packet; + mc13783_transfer.rxbuf = NULL; + mc13783_transfer.count = 1; + + i = -1; + + if (spi_transfer(&mc13783_transfer) && wait_for_transfer_complete()) + i = 1 - mc13783_transfer.count; + + mutex_unlock(&mc13783_spi_mutex); - return 1 - xfer.count; + return i; } uint32_t mc13783_write_masked(unsigned address, uint32_t data, uint32_t mask) { uint32_t old; - spi_lock(&mc13783_spi); + mutex_lock(&mc13783_spi_mutex); old = mc13783_read(address); @@ -238,86 +285,144 @@ uint32_t mc13783_write_masked(unsigned address, uint32_t data, uint32_t mask) old = MC13783_DATA_ERROR; } - spi_unlock(&mc13783_spi); + mutex_unlock(&mc13783_spi_mutex); return old; } -int mc13783_write_regset(const unsigned char *regs, const uint32_t *data, - int count) +uint32_t mc13783_read(unsigned address) { - int i; - struct spi_transfer xfer; - uint32_t packets[MC13783_NUM_REGS]; + uint32_t packet; - if ((unsigned)count > MC13783_NUM_REGS) - return -1; + if (address >= MC13783_NUM_REGS) + return MC13783_DATA_ERROR; + + packet = address << 25; + + mutex_lock(&mc13783_spi_mutex); + + mc13783_transfer.txbuf = &packet; + mc13783_transfer.rxbuf = &packet; + mc13783_transfer.count = 1; + + if (!spi_transfer(&mc13783_transfer) || !wait_for_transfer_complete()) + packet = MC13783_DATA_ERROR; + + mutex_unlock(&mc13783_spi_mutex); + + return packet; +} + +int mc13783_read_regs(const unsigned char *regs, uint32_t *buffer, + int count) +{ + int i; for (i = 0; i < count; i++) { - uint32_t reg = regs[i]; + unsigned reg = regs[i]; if (reg >= MC13783_NUM_REGS) return -1; - packets[i] = (1 << 31) | (reg << 25) | (data[i] & 0xffffff); + buffer[i] = reg << 25; } - xfer.txbuf = packets; - xfer.rxbuf = packets; - xfer.count = count; + mutex_lock(&mc13783_spi_mutex); - if (!spi_transfer(&mc13783_spi, &xfer)) - return -1; + mc13783_transfer.txbuf = buffer; + mc13783_transfer.rxbuf = buffer; + mc13783_transfer.count = count; + + i = -1; + + if (spi_transfer(&mc13783_transfer) && wait_for_transfer_complete()) + i = count - mc13783_transfer.count; - return count - xfer.count; + mutex_unlock(&mc13783_spi_mutex); + + return i; } -uint32_t mc13783_read(unsigned address) +int mc13783_write_regs(const unsigned char *regs, uint32_t *buffer, + int count) { - uint32_t packet; - struct spi_transfer xfer; + int i; - if (address >= MC13783_NUM_REGS) - return MC13783_DATA_ERROR; + for (i = 0; i < count; i++) + { + unsigned reg = regs[i]; - packet = address << 25; + if (reg >= MC13783_NUM_REGS) + return -1; - xfer.txbuf = &packet; - xfer.rxbuf = &packet; - xfer.count = 1; + buffer[i] = (1 << 31) | (reg << 25) | (buffer[i] & 0xffffff); + } - if (!spi_transfer(&mc13783_spi, &xfer)) - return MC13783_DATA_ERROR; + mutex_lock(&mc13783_spi_mutex); - return packet; + mc13783_transfer.txbuf = buffer; + mc13783_transfer.rxbuf = NULL; + mc13783_transfer.count = count; + + i = -1; + + if (spi_transfer(&mc13783_transfer) && wait_for_transfer_complete()) + i = count - mc13783_transfer.count; + + mutex_unlock(&mc13783_spi_mutex); + + return i; } -int mc13783_read_regset(const unsigned char *regs, uint32_t *buffer, - int count) +#if 0 /* Not needed right now */ +bool mc13783_read_async(struct spi_transfer_desc *xfer, + const unsigned char *regs, uint32_t *buffer, + int count, spi_transfer_cb_fn_type callback) { int i; - struct spi_transfer xfer; - - if ((unsigned)count > MC13783_NUM_REGS) - return -1; for (i = 0; i < count; i++) { unsigned reg = regs[i]; if (reg >= MC13783_NUM_REGS) - return -1; + return false; buffer[i] = reg << 25; } - xfer.txbuf = buffer; - xfer.rxbuf = buffer; - xfer.count = count; + xfer->node = &mc13783_spi; + xfer->txbuf = buffer; + xfer->rxbuf = buffer; + xfer->count = count; + xfer->callback = callback; - if (!spi_transfer(&mc13783_spi, &xfer)) - return -1; + return spi_transfer(xfer); +} +#endif + +bool mc13783_write_async(struct spi_transfer_desc *xfer, + const unsigned char *regs, uint32_t *buffer, + int count, spi_transfer_cb_fn_type callback) +{ + int i; + + for (i = 0; i < count; i++) + { + unsigned reg = regs[i]; + + if (reg >= MC13783_NUM_REGS) + return false; + + buffer[i] = (1 << 31) | (reg << 25) | (buffer[i] & 0xffffff); + } + + xfer->node = &mc13783_spi; + xfer->txbuf = buffer; + xfer->rxbuf = NULL; + xfer->count = count; + xfer->callback = callback; - return count - xfer.count; + return spi_transfer(xfer); } |