summaryrefslogtreecommitdiffstats
path: root/firmware/target/arm
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2009-02-02 02:38:21 +0000
committerMichael Sevakis <jethead71@rockbox.org>2009-02-02 02:38:21 +0000
commit1a00056f1f225ee0d1643d3e4e603de171f7ab9a (patch)
treea73a7d2124305c5578982f1fec872f640bca6b13 /firmware/target/arm
parent304aefe80256429e8c1cbdbb5afd1693d90041aa (diff)
downloadrockbox-1a00056f1f225ee0d1643d3e4e603de171f7ab9a.tar.gz
rockbox-1a00056f1f225ee0d1643d3e4e603de171f7ab9a.zip
i.MX31: Make SPI more tolerant by resetting and forcing a reconfigure of the interface if an error ever happens. Better handle PMIC GPIO interrupt; it definitely doesn't low-pulse PRIINT (remains high if sources become active again or stay active while acking) so needed rising edge may never happen in such a case-- use high-level detection rather than rising edge. Optimize the reg/clr/set/mod functions a bit since they get more regular use now.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19903 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm')
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c6
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/gpio-target.h1
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c8
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/spi-imx31.c22
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/system-imx31.c44
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