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:
parent
304aefe802
commit
1a00056f1f
5 changed files with 61 additions and 20 deletions
|
@ -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,
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue