summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 @@
29/* Describes single events for each GPIO1 pin */ 29/* Describes single events for each GPIO1 pin */
30static const struct gpio_event gpio1_events[] = 30static 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 */
130void mc13783_event(void) 136void 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
223static 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 */
224void spi_init(void) 233void 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
175void imx31_regmod32(volatile uint32_t *reg_p, uint32_t value, uint32_t mask) 175void __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
185void imx31_regset32(volatile uint32_t *reg_p, uint32_t mask) 191void __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
190void imx31_regclr32(volatile uint32_t *reg_p, uint32_t mask) 204void __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