diff options
Diffstat (limited to 'firmware/target/arm')
5 files changed, 61 insertions, 20 deletions
diff --git a/firmware/target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c index 37f6a00c3d..446932b308 100644 --- a/firmware/target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c @@ -29,10 +29,14 @@ /* Describes single events for each GPIO1 pin */ static const struct gpio_event gpio1_events[] = { + /* mc13783 keeps the PRIINT high (no low pulse) if other unmasked + * interrupts become active when clearing them or if a source being + * cleared becomes active at that time. Edge-detection will not get + * a rising edge in that case so use high-level sense. */ [MC13783_EVENT_ID-GPIO1_EVENT_FIRST] = { .mask = 1 << MC13783_GPIO_LINE, - .sense = GPIO_SENSE_RISING, + .sense = GPIO_SENSE_HIGH_LEVEL, .callback = mc13783_event, } }; diff --git a/firmware/target/arm/imx31/gigabeat-s/gpio-target.h b/firmware/target/arm/imx31/gigabeat-s/gpio-target.h index 0989f075be..0c213611ff 100644 --- a/firmware/target/arm/imx31/gigabeat-s/gpio-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/gpio-target.h @@ -24,6 +24,7 @@ #define GPIO_TARGET_H /* MC13783 GPIO pin info for this target */ +#define MC13783_GPIO_IMR GPIO1_IMR #define MC13783_GPIO_NUM GPIO1_NUM #define MC13783_GPIO_ISR GPIO1_ISR #define MC13783_GPIO_LINE 31 diff --git a/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c b/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c index 22987abf74..2c5af8d5b7 100644 --- a/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c @@ -98,6 +98,12 @@ static void mc13783_interrupt_thread(void) mc13783_write_regset(pmic_ints_regs, pending, 2); + /* Whatever is going to be serviced in this loop has been + * acknowledged. Reenable interrupt and if anything was still + * pending or became pending again, another signal will be + * generated. */ + imx31_regset32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE); + event = mc13783_event_list.events; event_last = event + mc13783_event_list.count; @@ -129,6 +135,8 @@ static void mc13783_interrupt_thread(void) /* GPIO interrupt handler for mc13783 */ 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); } diff --git a/firmware/target/arm/imx31/gigabeat-s/spi-imx31.c b/firmware/target/arm/imx31/gigabeat-s/spi-imx31.c index 815ffca21a..98604d1eef 100644 --- a/firmware/target/arm/imx31/gigabeat-s/spi-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/spi-imx31.c @@ -220,6 +220,15 @@ static bool spi_set_context(struct spi_node *node, return true; } +static void spi_reset(struct cspi_map * const base) +{ + /* Reset */ + base->conreg &= ~CSPI_CONREG_EN; + base->conreg |= CSPI_CONREG_EN; + base->intreg = 0; + base->statreg = CSPI_STATREG_TC | CSPI_STATREG_BO; +} + /* Initialize each of the used SPI descriptors */ void spi_init(void) { @@ -259,13 +268,9 @@ void spi_enable_module(struct spi_node *node) /* Enable clock-gating register */ imx31_clkctl_module_clock_gating(desc->cg, CGM_ON_ALL); - /* Reset */ - base->conreg &= ~CSPI_CONREG_EN; - base->conreg |= CSPI_CONREG_EN; - base->intreg = 0; - base->statreg = CSPI_STATREG_TC | CSPI_STATREG_BO; - + spi_reset(base); + desc->last = NULL; /* Enable interrupt at controller level */ avic_enable_int(desc->ints, IRQ, 6, desc->handler); } @@ -333,8 +338,9 @@ int spi_transfer(struct spi_node *node, struct spi_transfer *trans) if (wakeup_wait(&desc->w, HZ) != OBJ_WAIT_SUCCEEDED) { - base->intreg = 0; - base->conreg &= ~CSPI_CONREG_XCH; + base->intreg = 0; /* Stop SPI ints */ + spi_reset(base); /* Reset module (esp. to empty FIFOs) */ + desc->last = NULL; /* Force reconfigure */ retval = false; } } diff --git a/firmware/target/arm/imx31/gigabeat-s/system-imx31.c b/firmware/target/arm/imx31/gigabeat-s/system-imx31.c index 7454806d07..cb265af0a3 100644 --- a/firmware/target/arm/imx31/gigabeat-s/system-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/system-imx31.c @@ -172,24 +172,46 @@ void system_init(void) gpio_init(); } -void imx31_regmod32(volatile uint32_t *reg_p, uint32_t value, uint32_t mask) +void __attribute__((naked)) imx31_regmod32(volatile uint32_t *reg_p, + uint32_t value, + uint32_t mask) { - value &= mask; - mask = ~mask; - - int oldlevel = disable_interrupt_save(IRQ_FIQ_STATUS); - *reg_p = (*reg_p & mask) | value; - restore_interrupt(oldlevel); + asm volatile("and r1, r1, r2 \n" + "mrs ip, cpsr \n" + "cpsid if \n" + "ldr r3, [r0] \n" + "bic r3, r3, r2 \n" + "orr r3, r3, r1 \n" + "str r3, [r0] \n" + "msr cpsr_c, ip \n" + "bx lr \n"); + (void)reg_p; (void)value; (void)mask; } -void imx31_regset32(volatile uint32_t *reg_p, uint32_t mask) +void __attribute__((naked)) imx31_regset32(volatile uint32_t *reg_p, + uint32_t mask) { - imx31_regmod32(reg_p, mask, mask); + asm volatile("mrs r3, cpsr \n" + "cpsid if \n" + "ldr r2, [r0] \n" + "orr r2, r2, r1 \n" + "str r2, [r0] \n" + "msr cpsr_c, r3 \n" + "bx lr \n"); + (void)reg_p; (void)mask; } -void imx31_regclr32(volatile uint32_t *reg_p, uint32_t mask) +void __attribute__((naked)) imx31_regclr32(volatile uint32_t *reg_p, + uint32_t mask) { - imx31_regmod32(reg_p, 0, mask); + asm volatile("mrs r3, cpsr \n" + "cpsid if \n" + "ldr r2, [r0] \n" + "bic r2, r2, r1 \n" + "str r2, [r0] \n" + "msr cpsr_c, r3 \n" + "bx lr \n"); + (void)reg_p; (void)mask; } #ifdef BOOTLOADER |