1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Michael Sevakis 2009-02-02 02:38:21 +00:00
parent 304aefe802
commit 1a00056f1f
5 changed files with 61 additions and 20 deletions

View file

@ -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,
}
};

View file

@ -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

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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