diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2009-02-02 02:38:21 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2009-02-02 02:38:21 +0000 |
commit | 1a00056f1f225ee0d1643d3e4e603de171f7ab9a (patch) | |
tree | a73a7d2124305c5578982f1fec872f640bca6b13 | |
parent | 304aefe80256429e8c1cbdbb5afd1693d90041aa (diff) | |
download | rockbox-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
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 @@ | |||
29 | /* Describes single events for each GPIO1 pin */ | 29 | /* Describes single events for each GPIO1 pin */ |
30 | static const struct gpio_event gpio1_events[] = | 30 | static const struct gpio_event gpio1_events[] = |
31 | { | 31 | { |
32 | /* mc13783 keeps the PRIINT high (no low pulse) if other unmasked | ||
33 | * interrupts become active when clearing them or if a source being | ||
34 | * cleared becomes active at that time. Edge-detection will not get | ||
35 | * a rising edge in that case so use high-level sense. */ | ||
32 | [MC13783_EVENT_ID-GPIO1_EVENT_FIRST] = | 36 | [MC13783_EVENT_ID-GPIO1_EVENT_FIRST] = |
33 | { | 37 | { |
34 | .mask = 1 << MC13783_GPIO_LINE, | 38 | .mask = 1 << MC13783_GPIO_LINE, |
35 | .sense = GPIO_SENSE_RISING, | 39 | .sense = GPIO_SENSE_HIGH_LEVEL, |
36 | .callback = mc13783_event, | 40 | .callback = mc13783_event, |
37 | } | 41 | } |
38 | }; | 42 | }; |
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 @@ | |||
24 | #define GPIO_TARGET_H | 24 | #define GPIO_TARGET_H |
25 | 25 | ||
26 | /* MC13783 GPIO pin info for this target */ | 26 | /* MC13783 GPIO pin info for this target */ |
27 | #define MC13783_GPIO_IMR GPIO1_IMR | ||
27 | #define MC13783_GPIO_NUM GPIO1_NUM | 28 | #define MC13783_GPIO_NUM GPIO1_NUM |
28 | #define MC13783_GPIO_ISR GPIO1_ISR | 29 | #define MC13783_GPIO_ISR GPIO1_ISR |
29 | #define MC13783_GPIO_LINE 31 | 30 | #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) | |||
98 | 98 | ||
99 | mc13783_write_regset(pmic_ints_regs, pending, 2); | 99 | mc13783_write_regset(pmic_ints_regs, pending, 2); |
100 | 100 | ||
101 | /* Whatever is going to be serviced in this loop has been | ||
102 | * acknowledged. Reenable interrupt and if anything was still | ||
103 | * pending or became pending again, another signal will be | ||
104 | * generated. */ | ||
105 | imx31_regset32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE); | ||
106 | |||
101 | event = mc13783_event_list.events; | 107 | event = mc13783_event_list.events; |
102 | event_last = event + mc13783_event_list.count; | 108 | event_last = event + mc13783_event_list.count; |
103 | 109 | ||
@@ -129,6 +135,8 @@ static void mc13783_interrupt_thread(void) | |||
129 | /* GPIO interrupt handler for mc13783 */ | 135 | /* GPIO interrupt handler for mc13783 */ |
130 | void mc13783_event(void) | 136 | void mc13783_event(void) |
131 | { | 137 | { |
138 | /* Mask the interrupt (unmasked when PMIC thread services it). */ | ||
139 | imx31_regclr32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE); | ||
132 | MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE); | 140 | MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE); |
133 | wakeup_signal(&mc13783_wake); | 141 | wakeup_signal(&mc13783_wake); |
134 | } | 142 | } |
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, | |||
220 | return true; | 220 | return true; |
221 | } | 221 | } |
222 | 222 | ||
223 | static void spi_reset(struct cspi_map * const base) | ||
224 | { | ||
225 | /* Reset */ | ||
226 | base->conreg &= ~CSPI_CONREG_EN; | ||
227 | base->conreg |= CSPI_CONREG_EN; | ||
228 | base->intreg = 0; | ||
229 | base->statreg = CSPI_STATREG_TC | CSPI_STATREG_BO; | ||
230 | } | ||
231 | |||
223 | /* Initialize each of the used SPI descriptors */ | 232 | /* Initialize each of the used SPI descriptors */ |
224 | void spi_init(void) | 233 | void spi_init(void) |
225 | { | 234 | { |
@@ -259,13 +268,9 @@ void spi_enable_module(struct spi_node *node) | |||
259 | 268 | ||
260 | /* Enable clock-gating register */ | 269 | /* Enable clock-gating register */ |
261 | imx31_clkctl_module_clock_gating(desc->cg, CGM_ON_ALL); | 270 | imx31_clkctl_module_clock_gating(desc->cg, CGM_ON_ALL); |
262 | |||
263 | /* Reset */ | 271 | /* Reset */ |
264 | base->conreg &= ~CSPI_CONREG_EN; | 272 | spi_reset(base); |
265 | base->conreg |= CSPI_CONREG_EN; | 273 | desc->last = NULL; |
266 | base->intreg = 0; | ||
267 | base->statreg = CSPI_STATREG_TC | CSPI_STATREG_BO; | ||
268 | |||
269 | /* Enable interrupt at controller level */ | 274 | /* Enable interrupt at controller level */ |
270 | avic_enable_int(desc->ints, IRQ, 6, desc->handler); | 275 | avic_enable_int(desc->ints, IRQ, 6, desc->handler); |
271 | } | 276 | } |
@@ -333,8 +338,9 @@ int spi_transfer(struct spi_node *node, struct spi_transfer *trans) | |||
333 | 338 | ||
334 | if (wakeup_wait(&desc->w, HZ) != OBJ_WAIT_SUCCEEDED) | 339 | if (wakeup_wait(&desc->w, HZ) != OBJ_WAIT_SUCCEEDED) |
335 | { | 340 | { |
336 | base->intreg = 0; | 341 | base->intreg = 0; /* Stop SPI ints */ |
337 | base->conreg &= ~CSPI_CONREG_XCH; | 342 | spi_reset(base); /* Reset module (esp. to empty FIFOs) */ |
343 | desc->last = NULL; /* Force reconfigure */ | ||
338 | retval = false; | 344 | retval = false; |
339 | } | 345 | } |
340 | } | 346 | } |
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) | |||
172 | gpio_init(); | 172 | gpio_init(); |
173 | } | 173 | } |
174 | 174 | ||
175 | void imx31_regmod32(volatile uint32_t *reg_p, uint32_t value, uint32_t mask) | 175 | void __attribute__((naked)) imx31_regmod32(volatile uint32_t *reg_p, |
176 | uint32_t value, | ||
177 | uint32_t mask) | ||
176 | { | 178 | { |
177 | value &= mask; | 179 | asm volatile("and r1, r1, r2 \n" |
178 | mask = ~mask; | 180 | "mrs ip, cpsr \n" |
179 | 181 | "cpsid if \n" | |
180 | int oldlevel = disable_interrupt_save(IRQ_FIQ_STATUS); | 182 | "ldr r3, [r0] \n" |
181 | *reg_p = (*reg_p & mask) | value; | 183 | "bic r3, r3, r2 \n" |
182 | restore_interrupt(oldlevel); | 184 | "orr r3, r3, r1 \n" |
185 | "str r3, [r0] \n" | ||
186 | "msr cpsr_c, ip \n" | ||
187 | "bx lr \n"); | ||
188 | (void)reg_p; (void)value; (void)mask; | ||
183 | } | 189 | } |
184 | 190 | ||
185 | void imx31_regset32(volatile uint32_t *reg_p, uint32_t mask) | 191 | void __attribute__((naked)) imx31_regset32(volatile uint32_t *reg_p, |
192 | uint32_t mask) | ||
186 | { | 193 | { |
187 | imx31_regmod32(reg_p, mask, mask); | 194 | asm volatile("mrs r3, cpsr \n" |
195 | "cpsid if \n" | ||
196 | "ldr r2, [r0] \n" | ||
197 | "orr r2, r2, r1 \n" | ||
198 | "str r2, [r0] \n" | ||
199 | "msr cpsr_c, r3 \n" | ||
200 | "bx lr \n"); | ||
201 | (void)reg_p; (void)mask; | ||
188 | } | 202 | } |
189 | 203 | ||
190 | void imx31_regclr32(volatile uint32_t *reg_p, uint32_t mask) | 204 | void __attribute__((naked)) imx31_regclr32(volatile uint32_t *reg_p, |
205 | uint32_t mask) | ||
191 | { | 206 | { |
192 | imx31_regmod32(reg_p, 0, mask); | 207 | asm volatile("mrs r3, cpsr \n" |
208 | "cpsid if \n" | ||
209 | "ldr r2, [r0] \n" | ||
210 | "bic r2, r2, r1 \n" | ||
211 | "str r2, [r0] \n" | ||
212 | "msr cpsr_c, r3 \n" | ||
213 | "bx lr \n"); | ||
214 | (void)reg_p; (void)mask; | ||
193 | } | 215 | } |
194 | 216 | ||
195 | #ifdef BOOTLOADER | 217 | #ifdef BOOTLOADER |