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 */
|
/* Describes single events for each GPIO1 pin */
|
||||||
static const struct gpio_event gpio1_events[] =
|
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] =
|
[MC13783_EVENT_ID-GPIO1_EVENT_FIRST] =
|
||||||
{
|
{
|
||||||
.mask = 1 << MC13783_GPIO_LINE,
|
.mask = 1 << MC13783_GPIO_LINE,
|
||||||
.sense = GPIO_SENSE_RISING,
|
.sense = GPIO_SENSE_HIGH_LEVEL,
|
||||||
.callback = mc13783_event,
|
.callback = mc13783_event,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#define GPIO_TARGET_H
|
#define GPIO_TARGET_H
|
||||||
|
|
||||||
/* MC13783 GPIO pin info for this target */
|
/* MC13783 GPIO pin info for this target */
|
||||||
|
#define MC13783_GPIO_IMR GPIO1_IMR
|
||||||
#define MC13783_GPIO_NUM GPIO1_NUM
|
#define MC13783_GPIO_NUM GPIO1_NUM
|
||||||
#define MC13783_GPIO_ISR GPIO1_ISR
|
#define MC13783_GPIO_ISR GPIO1_ISR
|
||||||
#define MC13783_GPIO_LINE 31
|
#define MC13783_GPIO_LINE 31
|
||||||
|
|
|
@ -98,6 +98,12 @@ static void mc13783_interrupt_thread(void)
|
||||||
|
|
||||||
mc13783_write_regset(pmic_ints_regs, pending, 2);
|
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 = mc13783_event_list.events;
|
||||||
event_last = event + mc13783_event_list.count;
|
event_last = event + mc13783_event_list.count;
|
||||||
|
|
||||||
|
@ -129,6 +135,8 @@ static void mc13783_interrupt_thread(void)
|
||||||
/* GPIO interrupt handler for mc13783 */
|
/* GPIO interrupt handler for mc13783 */
|
||||||
void mc13783_event(void)
|
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);
|
MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE);
|
||||||
wakeup_signal(&mc13783_wake);
|
wakeup_signal(&mc13783_wake);
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,6 +220,15 @@ static bool spi_set_context(struct spi_node *node,
|
||||||
return true;
|
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 */
|
/* Initialize each of the used SPI descriptors */
|
||||||
void spi_init(void)
|
void spi_init(void)
|
||||||
{
|
{
|
||||||
|
@ -259,13 +268,9 @@ void spi_enable_module(struct spi_node *node)
|
||||||
|
|
||||||
/* Enable clock-gating register */
|
/* Enable clock-gating register */
|
||||||
imx31_clkctl_module_clock_gating(desc->cg, CGM_ON_ALL);
|
imx31_clkctl_module_clock_gating(desc->cg, CGM_ON_ALL);
|
||||||
|
|
||||||
/* Reset */
|
/* Reset */
|
||||||
base->conreg &= ~CSPI_CONREG_EN;
|
spi_reset(base);
|
||||||
base->conreg |= CSPI_CONREG_EN;
|
desc->last = NULL;
|
||||||
base->intreg = 0;
|
|
||||||
base->statreg = CSPI_STATREG_TC | CSPI_STATREG_BO;
|
|
||||||
|
|
||||||
/* Enable interrupt at controller level */
|
/* Enable interrupt at controller level */
|
||||||
avic_enable_int(desc->ints, IRQ, 6, desc->handler);
|
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)
|
if (wakeup_wait(&desc->w, HZ) != OBJ_WAIT_SUCCEEDED)
|
||||||
{
|
{
|
||||||
base->intreg = 0;
|
base->intreg = 0; /* Stop SPI ints */
|
||||||
base->conreg &= ~CSPI_CONREG_XCH;
|
spi_reset(base); /* Reset module (esp. to empty FIFOs) */
|
||||||
|
desc->last = NULL; /* Force reconfigure */
|
||||||
retval = false;
|
retval = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,24 +172,46 @@ void system_init(void)
|
||||||
gpio_init();
|
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;
|
asm volatile("and r1, r1, r2 \n"
|
||||||
mask = ~mask;
|
"mrs ip, cpsr \n"
|
||||||
|
"cpsid if \n"
|
||||||
int oldlevel = disable_interrupt_save(IRQ_FIQ_STATUS);
|
"ldr r3, [r0] \n"
|
||||||
*reg_p = (*reg_p & mask) | value;
|
"bic r3, r3, r2 \n"
|
||||||
restore_interrupt(oldlevel);
|
"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
|
#ifdef BOOTLOADER
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue