summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2008-04-12 16:56:45 +0000
committerMichael Sevakis <jethead71@rockbox.org>2008-04-12 16:56:45 +0000
commita7af9e4a7f25f5a32306c74e95a677e6c85f399e (patch)
tree5df60e8382b69cf943840852269ea9387d42ea46
parentddfd787c54d78104dac4ed144ff6cb6df8617a0e (diff)
downloadrockbox-a7af9e4a7f25f5a32306c74e95a677e6c85f399e.tar.gz
rockbox-a7af9e4a7f25f5a32306c74e95a677e6c85f399e.zip
Add GPIO manager. Get the PMIC interrupt handling working (along with power button and HP detect). Add some reg field defined instead of using raw numbers. Add PMIC info to debug ports screen. Refine PMIC driver ops a little bit.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17086 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/SOURCES2
-rw-r--r--firmware/export/config-gigabeat-s.h5
-rwxr-xr-xfirmware/export/imx31l.h54
-rw-r--r--firmware/export/mc13783.h17
-rw-r--r--firmware/export/thread.h12
-rw-r--r--firmware/target/arm/imx31/debug-imx31.c48
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/avic-imx31.c2
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c4
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/button-imx31.c38
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/button-target.h3
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c39
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/gpio-imx31.c207
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/gpio-imx31.h77
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/gpio-target.h31
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c151
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/power-imx31.c10
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/system-imx31.c2
17 files changed, 655 insertions, 47 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 8229fecca0..c0f6c81d9f 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -650,6 +650,8 @@ target/arm/imx31/gigabeat-s/backlight-imx31.c
650target/arm/imx31/gigabeat-s/button-imx31.c 650target/arm/imx31/gigabeat-s/button-imx31.c
651target/arm/imx31/gigabeat-s/clkctl-imx31.c 651target/arm/imx31/gigabeat-s/clkctl-imx31.c
652target/arm/imx31/gigabeat-s/dma_start.c 652target/arm/imx31/gigabeat-s/dma_start.c
653target/arm/imx31/gigabeat-s/gpio-imx31.c
654target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c
653target/arm/imx31/gigabeat-s/kernel-imx31.c 655target/arm/imx31/gigabeat-s/kernel-imx31.c
654target/arm/imx31/gigabeat-s/i2c-imx31.c 656target/arm/imx31/gigabeat-s/i2c-imx31.c
655target/arm/imx31/gigabeat-s/i2s-imx31.c 657target/arm/imx31/gigabeat-s/i2s-imx31.c
diff --git a/firmware/export/config-gigabeat-s.h b/firmware/export/config-gigabeat-s.h
index 09f5e18ecc..3fc226ae59 100644
--- a/firmware/export/config-gigabeat-s.h
+++ b/firmware/export/config-gigabeat-s.h
@@ -73,6 +73,8 @@
73#define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | \ 73#define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | \
74 SAMPR_CAP_11) 74 SAMPR_CAP_11)
75 75
76#define HAVE_HEADPHONE_DETECTION
77
76#ifndef SIMULATOR 78#ifndef SIMULATOR
77 79
78/* The LCD on a Gigabeat is 240x320 - it is portrait */ 80/* The LCD on a Gigabeat is 240x320 - it is portrait */
@@ -86,6 +88,9 @@
86/* Define the bitmask of serial interface modules (CSPI) used */ 88/* Define the bitmask of serial interface modules (CSPI) used */
87#define SPI_MODULE_MASK (USE_CSPI2_MODULE) 89#define SPI_MODULE_MASK (USE_CSPI2_MODULE)
88 90
91/* Define this if target has an additional number of threads specific to it */
92#define TARGET_EXTRA_THREADS 1
93
89/* Type of mobile power - check this out */ 94/* Type of mobile power - check this out */
90#define BATTERY_CAPACITY_DEFAULT 2000 /* default battery capacity */ 95#define BATTERY_CAPACITY_DEFAULT 2000 /* default battery capacity */
91#define BATTERY_CAPACITY_MIN 1500 /* min. capacity selectable */ 96#define BATTERY_CAPACITY_MIN 1500 /* min. capacity selectable */
diff --git a/firmware/export/imx31l.h b/firmware/export/imx31l.h
index 7dc2659b33..3e7abe344b 100755
--- a/firmware/export/imx31l.h
+++ b/firmware/export/imx31l.h
@@ -491,29 +491,37 @@
491#define EPITSR_OCIF (1 << 0) 491#define EPITSR_OCIF (1 << 0)
492 492
493/* GPIO */ 493/* GPIO */
494#define GPIO1_DR (*(REG32_PTR_T)(GPIO1_BASE_ADDR+0x00)) 494#define GPIO_DR_I 0x00 /* Offset - 0x00 */
495#define GPIO1_GDIR (*(REG32_PTR_T)(GPIO1_BASE_ADDR+0x04)) 495#define GPIO_GDIR_I 0x01 /* Offset - 0x04 */
496#define GPIO1_PSR (*(REG32_PTR_T)(GPIO1_BASE_ADDR+0x08)) 496#define GPIO_PSR_I 0x02 /* Offset - 0x08 */
497#define GPIO1_ICR1 (*(REG32_PTR_T)(GPIO1_BASE_ADDR+0x0C)) 497#define GPIO_ICR1_I 0x03 /* Offset - 0x0C */
498#define GPIO1_ICR2 (*(REG32_PTR_T)(GPIO1_BASE_ADDR+0x10)) 498#define GPIO_ICR2_I 0x04 /* Offset - 0x10 */
499#define GPIO1_IMR (*(REG32_PTR_T)(GPIO1_BASE_ADDR+0x14)) 499#define GPIO_IMR_I 0x05 /* Offset - 0x14 */
500#define GPIO1_ISR (*(REG32_PTR_T)(GPIO1_BASE_ADDR+0x18)) 500#define GPIO_ISR_I 0x06 /* Offset - 0x18 */
501 501
502#define GPIO2_DR (*(REG32_PTR_T)(GPIO2_BASE_ADDR+0x00)) 502#define GPIO1_DR (((REG32_PTR_T)GPIO1_BASE_ADDR)[GPIO_DR_I])
503#define GPIO2_GDIR (*(REG32_PTR_T)(GPIO2_BASE_ADDR+0x04)) 503#define GPIO1_GDIR (((REG32_PTR_T)GPIO1_BASE_ADDR)[GPIO_GDIR_I])
504#define GPIO2_PSR (*(REG32_PTR_T)(GPIO2_BASE_ADDR+0x08)) 504#define GPIO1_PSR (((REG32_PTR_T)GPIO1_BASE_ADDR)[GPIO_PSR_I])
505#define GPIO2_ICR1 (*(REG32_PTR_T)(GPIO2_BASE_ADDR+0x0C)) 505#define GPIO1_ICR1 (((REG32_PTR_T)GPIO1_BASE_ADDR)[GPIO_ICR1_I])
506#define GPIO2_ICR2 (*(REG32_PTR_T)(GPIO2_BASE_ADDR+0x10)) 506#define GPIO1_ICR2 (((REG32_PTR_T)GPIO1_BASE_ADDR)[GPIO_ICR2_I])
507#define GPIO2_IMR (*(REG32_PTR_T)(GPIO2_BASE_ADDR+0x14)) 507#define GPIO1_IMR (((REG32_PTR_T)GPIO1_BASE_ADDR)[GPIO_IMR_I])
508#define GPIO2_ISR (*(REG32_PTR_T)(GPIO2_BASE_ADDR+0x18)) 508#define GPIO1_ISR (((REG32_PTR_T)GPIO1_BASE_ADDR)[GPIO_ISR_I])
509 509
510#define GPIO3_DR (*(REG32_PTR_T)(GPIO3_BASE_ADDR+0x00)) 510#define GPIO2_DR (((REG32_PTR_T)GPIO2_BASE_ADDR)[GPIO_DR_I])
511#define GPIO3_GDIR (*(REG32_PTR_T)(GPIO3_BASE_ADDR+0x04)) 511#define GPIO2_GDIR (((REG32_PTR_T)GPIO2_BASE_ADDR)[GPIO_GDIR_I])
512#define GPIO3_PSR (*(REG32_PTR_T)(GPIO3_BASE_ADDR+0x08)) 512#define GPIO2_PSR (((REG32_PTR_T)GPIO2_BASE_ADDR)[GPIO_PSR_I])
513#define GPIO3_ICR1 (*(REG32_PTR_T)(GPIO3_BASE_ADDR+0x0C)) 513#define GPIO2_ICR1 (((REG32_PTR_T)GPIO2_BASE_ADDR)[GPIO_ICR1_I])
514#define GPIO3_ICR2 (*(REG32_PTR_T)(GPIO3_BASE_ADDR+0x10)) 514#define GPIO2_ICR2 (((REG32_PTR_T)GPIO2_BASE_ADDR)[GPIO_ICR2_I])
515#define GPIO3_IMR (*(REG32_PTR_T)(GPIO3_BASE_ADDR+0x14)) 515#define GPIO2_IMR (((REG32_PTR_T)GPIO2_BASE_ADDR)[GPIO_IMR_I])
516#define GPIO3_ISR (*(REG32_PTR_T)(GPIO3_BASE_ADDR+0x18)) 516#define GPIO2_ISR (((REG32_PTR_T)GPIO2_BASE_ADDR)[GPIO_ISR_I])
517
518#define GPIO3_DR (((REG32_PTR_T)GPIO3_BASE_ADDR)[GPIO_DR_I])
519#define GPIO3_GDIR (((REG32_PTR_T)GPIO3_BASE_ADDR)[GPIO_GDIR_I])
520#define GPIO3_PSR (((REG32_PTR_T)GPIO3_BASE_ADDR)[GPIO_PSR_I])
521#define GPIO3_ICR1 (((REG32_PTR_T)GPIO3_BASE_ADDR)[GPIO_ICR1_I])
522#define GPIO3_ICR2 (((REG32_PTR_T)GPIO3_BASE_ADDR)[GPIO_ICR2_I])
523#define GPIO3_IMR (((REG32_PTR_T)GPIO3_BASE_ADDR)[GPIO_IMR_I])
524#define GPIO3_ISR (((REG32_PTR_T)GPIO3_BASE_ADDR)[GPIO_ISR_I])
517 525
518/* CSPI */ 526/* CSPI */
519#define CSPI_RXDATA_I 0x00 /* Offset - 0x00 */ 527#define CSPI_RXDATA_I 0x00 /* Offset - 0x00 */
diff --git a/firmware/export/mc13783.h b/firmware/export/mc13783.h
index fe9ff74e33..264c0bac4f 100644
--- a/firmware/export/mc13783.h
+++ b/firmware/export/mc13783.h
@@ -88,12 +88,25 @@ enum mc13783_regs_enum
88 MC13783_NUM_REGS, 88 MC13783_NUM_REGS,
89}; 89};
90 90
91/* INTERRUPT_STATUS1, INTERRUPT_MASK1, INTERRUPT_SENSE1 */
92#define MC13783_HSL (1 << 0)
93#define MC13783_ON1B (1 << 3)
94#define MC13783_ON2B (1 << 4)
95
96/* POWER_CONTROL0 */
97#define MC13783_USEROFFSPI (1 << 3)
98
99/* LED_CONTROL0 */
100#define MC13783_LEDEN (1 << 0)
101
91void mc13783_init(void); 102void mc13783_init(void);
92void mc13783_set(unsigned address, uint32_t bits); 103uint32_t mc13783_set(unsigned address, uint32_t bits);
93void mc13783_clear(unsigned address, uint32_t bits); 104uint32_t mc13783_clear(unsigned address, uint32_t bits);
94int mc13783_write(unsigned address, uint32_t data); 105int mc13783_write(unsigned address, uint32_t data);
95int mc13783_write_multiple(unsigned start, const uint32_t *buffer, int count); 106int mc13783_write_multiple(unsigned start, const uint32_t *buffer, int count);
107int mc13783_write_regset(const unsigned char *regs, const uint32_t *data, int count);
96uint32_t mc13783_read(unsigned address); 108uint32_t mc13783_read(unsigned address);
97int mc13783_read_multiple(unsigned start, uint32_t *buffer, int count); 109int mc13783_read_multiple(unsigned start, uint32_t *buffer, int count);
110int mc13783_read_regset(const unsigned char *regs, uint32_t *buffer, int count);
98 111
99#endif /* _MC13783_H_ */ 112#endif /* _MC13783_H_ */
diff --git a/firmware/export/thread.h b/firmware/export/thread.h
index 8c2338715c..eea58975a1 100644
--- a/firmware/export/thread.h
+++ b/firmware/export/thread.h
@@ -62,15 +62,21 @@
62#if CONFIG_CODEC == SWCODEC 62#if CONFIG_CODEC == SWCODEC
63 63
64#ifdef HAVE_RECORDING 64#ifdef HAVE_RECORDING
65#define MAXTHREADS 18 65#define BASETHREADS 18
66#else 66#else
67#define MAXTHREADS 17 67#define BASETHREADS 17
68#endif 68#endif
69 69
70#else 70#else
71#define MAXTHREADS 11 71#define BASETHREADS 11
72#endif /* CONFIG_CODE == * */ 72#endif /* CONFIG_CODE == * */
73 73
74#ifndef TARGET_EXTRA_THREADS
75#define TARGET_EXTRA_THREADS 0
76#endif
77
78#define MAXTHREADS (BASETHREADS+TARGET_EXTRA_THREADS)
79
74#define DEFAULT_STACK_SIZE 0x400 /* Bytes */ 80#define DEFAULT_STACK_SIZE 0x400 /* Bytes */
75 81
76#ifndef SIMULATOR 82#ifndef SIMULATOR
diff --git a/firmware/target/arm/imx31/debug-imx31.c b/firmware/target/arm/imx31/debug-imx31.c
index ab8db78063..7f1c9166d6 100644
--- a/firmware/target/arm/imx31/debug-imx31.c
+++ b/firmware/target/arm/imx31/debug-imx31.c
@@ -24,6 +24,7 @@
24#include "sprintf.h" 24#include "sprintf.h"
25#include "font.h" 25#include "font.h"
26#include "debug-target.h" 26#include "debug-target.h"
27#include "mc13783.h"
27 28
28bool __dbg_hw_info(void) 29bool __dbg_hw_info(void)
29{ 30{
@@ -34,6 +35,43 @@ bool __dbg_ports(void)
34{ 35{
35 char buf[50]; 36 char buf[50];
36 int line; 37 int line;
38 int i;
39
40 static const char pmic_regset[] =
41 {
42 MC13783_INTERRUPT_STATUS0,
43 MC13783_INTERRUPT_SENSE0,
44 MC13783_INTERRUPT_STATUS1,
45 MC13783_INTERRUPT_SENSE1,
46 MC13783_RTC_TIME,
47 MC13783_RTC_ALARM,
48 MC13783_RTC_DAY,
49 MC13783_RTC_DAY_ALARM,
50 MC13783_ADC0,
51 MC13783_ADC1,
52 MC13783_ADC2,
53 MC13783_ADC3,
54 MC13783_ADC4,
55 };
56
57 static const char *pmic_regnames[ARRAYLEN(pmic_regset)] =
58 {
59 "Int Stat0 ",
60 "Int Sense0",
61 "Int Stat1 ",
62 "Int Sense1",
63 "RTC Time ",
64 "RTC Alarm ",
65 "RTC Day ",
66 "RTC Day Al",
67 "ADC0 ",
68 "ADC1 ",
69 "ADC2 ",
70 "ADC3 ",
71 "ADC4 ",
72 };
73
74 uint32_t pmic_regs[ARRAYLEN(pmic_regset)];
37 75
38 lcd_setmargins(0, 0); 76 lcd_setmargins(0, 0);
39 lcd_clear_display(); 77 lcd_clear_display();
@@ -84,6 +122,16 @@ bool __dbg_ports(void)
84 snprintf(buf, sizeof(buf), " ISR: %08lx", GPIO3_ISR); 122 snprintf(buf, sizeof(buf), " ISR: %08lx", GPIO3_ISR);
85 lcd_puts(0, line++, buf); line++; 123 lcd_puts(0, line++, buf); line++;
86 124
125 lcd_puts(0, line++, "PMIC Registers"); line++;
126
127 mc13783_read_regset(pmic_regset, pmic_regs, ARRAYLEN(pmic_regs));
128
129 for (i = 0; i < (int)ARRAYLEN(pmic_regs); i++)
130 {
131 snprintf(buf, sizeof(buf), "%s: %08lx", pmic_regnames[i], pmic_regs[i]);
132 lcd_puts(0, line++, buf);
133 }
134
87 lcd_update(); 135 lcd_update();
88 if (button_get_w_tmo(HZ/10) == (DEBUG_CANCEL|BUTTON_REL)) 136 if (button_get_w_tmo(HZ/10) == (DEBUG_CANCEL|BUTTON_REL))
89 return false; 137 return false;
diff --git a/firmware/target/arm/imx31/gigabeat-s/avic-imx31.c b/firmware/target/arm/imx31/gigabeat-s/avic-imx31.c
index 194bc11ed6..6b64bfad77 100644
--- a/firmware/target/arm/imx31/gigabeat-s/avic-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/avic-imx31.c
@@ -43,7 +43,7 @@ static const char * avic_int_names[64] =
43 "EXT_SENS1", "EXT_SENS2", "EXT_WDOG", "EXT_TV" 43 "EXT_SENS1", "EXT_SENS2", "EXT_WDOG", "EXT_TV"
44}; 44};
45 45
46static void UIE_VECTOR(void) 46void UIE_VECTOR(void)
47{ 47{
48 int mode; 48 int mode;
49 long offset; 49 long offset;
diff --git a/firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c b/firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c
index 051b1c8479..1a41f0c53e 100644
--- a/firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c
@@ -34,13 +34,13 @@ bool _backlight_init(void)
34void _backlight_on(void) 34void _backlight_on(void)
35{ 35{
36 /* LEDEN=1 */ 36 /* LEDEN=1 */
37 mc13783_set(MC13783_LED_CONTROL0, (1 << 0)); 37 mc13783_set(MC13783_LED_CONTROL0, MC13783_LEDEN);
38} 38}
39 39
40void _backlight_off(void) 40void _backlight_off(void)
41{ 41{
42 /* LEDEN=0 */ 42 /* LEDEN=0 */
43 mc13783_clear(MC13783_LED_CONTROL0, (1 << 0)); 43 mc13783_clear(MC13783_LED_CONTROL0, MC13783_LEDEN);
44} 44}
45 45
46/* Assumes that the backlight has been initialized */ 46/* Assumes that the backlight has been initialized */
diff --git a/firmware/target/arm/imx31/gigabeat-s/button-imx31.c b/firmware/target/arm/imx31/gigabeat-s/button-imx31.c
index 602f41abb9..c85fe5e37e 100644
--- a/firmware/target/arm/imx31/gigabeat-s/button-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/button-imx31.c
@@ -29,7 +29,8 @@
29/* Most code in here is taken from the Linux BSP provided by Freescale 29/* Most code in here is taken from the Linux BSP provided by Freescale
30 * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. */ 30 * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. */
31 31
32static uint32_t int_btn = BUTTON_NONE; 32static bool headphones_detect = false;
33static uint32_t int_btn = BUTTON_NONE;
33static bool hold_button = false; 34static bool hold_button = false;
34static bool hold_button_old = false; 35static bool hold_button_old = false;
35#define _button_hold() (GPIO3_DR & 0x10) 36#define _button_hold() (GPIO3_DR & 0x10)
@@ -48,7 +49,8 @@ static __attribute__((interrupt("IRQ"))) void KPP_HANDLER(void)
48 unsigned short reg_val; 49 unsigned short reg_val;
49 int col, row; 50 int col, row;
50 int i; 51 int i;
51 int button = BUTTON_NONE; 52 /* Power button is handled separately on PMIC */
53 int button = int_btn & BUTTON_POWER;
52 54
53 /* 1. Disable both (depress and release) keypad interrupts. */ 55 /* 1. Disable both (depress and release) keypad interrupts. */
54 KPP_KPSR &= ~(KPP_KPSR_KRIE | KPP_KPSR_KDIE); 56 KPP_KPSR &= ~(KPP_KPSR_KRIE | KPP_KPSR_KDIE);
@@ -161,3 +163,35 @@ int button_read_device(void)
161 /* If hold, ignore any pressed button */ 163 /* If hold, ignore any pressed button */
162 return hold_button ? BUTTON_NONE : int_btn; 164 return hold_button ? BUTTON_NONE : int_btn;
163} 165}
166
167/* This is called from the mc13783 interrupt thread */
168void button_power_set_state(bool pressed)
169{
170 /* Prevent KPP_HANDLER from changing things */
171 int oldlevel = disable_irq_save();
172
173 if (pressed)
174 {
175 int_btn |= BUTTON_POWER;
176 }
177 else
178 {
179 int_btn &= ~BUTTON_POWER;
180 }
181
182 restore_irq(oldlevel);
183}
184
185/* This is called from the mc13783 interrupt thread */
186void set_headphones_inserted(bool inserted)
187{
188 headphones_detect = inserted;
189}
190
191/* This is called from the mc13783 interrupt thread */
192/* TODO: Just do a post to the button queue directly - implement the
193 * appropriate variant in the driver. */
194bool headphones_inserted(void)
195{
196 return headphones_detect;
197}
diff --git a/firmware/target/arm/imx31/gigabeat-s/button-target.h b/firmware/target/arm/imx31/gigabeat-s/button-target.h
index 33f018e0bf..836a4c02cd 100644
--- a/firmware/target/arm/imx31/gigabeat-s/button-target.h
+++ b/firmware/target/arm/imx31/gigabeat-s/button-target.h
@@ -27,6 +27,9 @@
27bool button_hold(void); 27bool button_hold(void);
28void button_init_device(void); 28void button_init_device(void);
29int button_read_device(void); 29int button_read_device(void);
30void button_power_set_state(bool pressed);
31void set_headphones_inserted(bool inserted);
32bool headphones_inserted(void);
30 33
31/* Toshiba Gigabeat specific button codes */ 34/* Toshiba Gigabeat specific button codes */
32 35
diff --git a/firmware/target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c
new file mode 100644
index 0000000000..cfbb7fcc4c
--- /dev/null
+++ b/firmware/target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c
@@ -0,0 +1,39 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2008 by Michael Sevakis
11 *
12 * Gigabeat S GPIO interrupt event descriptions
13 *
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "config.h"
22#include "system.h"
23#include "gpio-imx31.h"
24
25extern int mc13783_event(void);
26
27static const struct gpio_event gpio1_events =
28{
29 .line = MC13783_GPIO_LINE,
30 .sense = GPIO_SENSE_RISING,
31 .callback = mc13783_event,
32};
33
34const struct gpio_event_list gpio1_event_list =
35{
36 .priority = 7,
37 .count = 1,
38 .events = &gpio1_events,
39};
diff --git a/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.c b/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.c
new file mode 100644
index 0000000000..a7427f16c0
--- /dev/null
+++ b/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.c
@@ -0,0 +1,207 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2008 by Michael Sevakis
11 *
12 * IMX31 GPIO event manager
13 *
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "config.h"
22#include "system.h"
23#include "avic-imx31.h"
24#include "gpio-imx31.h"
25
26/* UIE vector found in avic-imx31.c */
27extern void UIE_VECTOR(void);
28
29/* Event lists are allocated for the specific target */
30#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
31static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void);
32extern const struct gpio_event_list gpio1_event_list;
33#endif
34
35#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
36static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void);
37extern const struct gpio_event_list gpio2_event_list;
38#endif
39
40#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
41static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void);
42extern const struct gpio_event_list gpio3_event_list;
43#endif
44
45static struct gpio_module_descriptor
46{
47 volatile unsigned long *base; /* Module base address */
48 enum IMX31_INT_LIST ints; /* AVIC int number */
49 void (*handler)(void); /* Interrupt function */
50 const struct gpio_event_list *list; /* Event handler list */
51} gpio_descs[GPIO_NUM_GPIO] =
52{
53#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
54 {
55 .base = (unsigned long *)GPIO1_BASE_ADDR,
56 .ints = GPIO1,
57 .handler = GPIO1_HANDLER,
58 },
59#endif
60#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
61 {
62 .base = (unsigned long *)GPIO2_BASE_ADDR,
63 .ints = GPIO2,
64 .handler = GPIO2_HANDLER,
65 },
66#endif
67#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
68 {
69 .base = (unsigned long *)GPIO3_BASE_ADDR,
70 .ints = GPIO3,
71 .handler = GPIO3_HANDLER,
72 },
73#endif
74};
75
76static void gpio_call_events(enum gpio_module_number gpio)
77{
78 const struct gpio_module_descriptor * const desc = &gpio_descs[gpio];
79 const struct gpio_event_list * const list = desc->list;
80 volatile unsigned long * const base = desc->base;
81 unsigned i;
82
83 /* Intersect pending and unmasked bits */
84 unsigned long pending = base[GPIO_ISR_I] & base[GPIO_IMR_I];
85
86 /* Call each event handler in order */
87 for (i = 0; i < list->count; i++)
88 {
89 const struct gpio_event * const event = &list->events[i];
90 unsigned long bit = 1ul << event->line;
91
92 if ((pending & bit) && event->callback())
93 pending &= ~bit;
94 }
95
96 if (pending != 0)
97 {
98 /* Wasn't handled */
99 UIE_VECTOR();
100 }
101}
102
103#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
104static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void)
105{
106 gpio_call_events(GPIO1_NUM);
107}
108#endif
109
110#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
111static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void)
112{
113 gpio_call_events(GPIO2_NUM);
114}
115#endif
116
117#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
118static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void)
119{
120 gpio_call_events(GPIO3_NUM);
121}
122#endif
123
124void gpio_init(void)
125{
126 /* Mask-out GPIO interrupts - enable what's wanted later */
127 GPIO1_IMR = 0;
128 GPIO2_IMR = 0;
129 GPIO3_IMR = 0;
130
131 /* Init the externally-defined event lists for each port */
132#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
133 gpio_descs[GPIO1_NUM].list = &gpio1_event_list;
134#endif
135#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
136 gpio_descs[GPIO2_NUM].list = &gpio2_event_list;
137#endif
138#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
139 gpio_descs[GPIO3_NUM].list = &gpio3_event_list;
140#endif
141}
142
143bool gpio_enable_event(enum gpio_module_number gpio, unsigned id)
144{
145 const struct gpio_module_descriptor * const desc = &gpio_descs[gpio];
146 const struct gpio_event * const event = &desc->list->events[id];
147 volatile unsigned long * const base = desc->base;
148 volatile unsigned long * icr;
149 unsigned long mask;
150 unsigned long imr;
151 int shift;
152
153 if (id >= desc->list->count)
154 return false;
155
156 int oldlevel = disable_irq_save();
157
158 imr = base[GPIO_IMR_I];
159
160 if (imr == 0)
161 {
162 /* First enabled interrupt for this GPIO */
163 avic_enable_int(desc->ints, IRQ, desc->list->priority,
164 desc->handler);
165 }
166
167 /* Set the line sense */
168 icr = &base[GPIO_ICR1_I] + event->line / 16;
169 shift = 2*(event->line % 16);
170 mask = GPIO_SENSE_CONFIG_MASK << shift;
171
172 *icr = (*icr & ~mask) | ((event->sense << shift) & mask);
173
174 /* Unmask the line */
175 base[GPIO_IMR_I] = imr | (1ul << event->line);
176
177 restore_irq(oldlevel);
178
179 return true;
180}
181
182void gpio_disable_event(enum gpio_module_number gpio, unsigned id)
183{
184 const struct gpio_module_descriptor * const desc = &gpio_descs[gpio];
185 const struct gpio_event * const event = &desc->list->events[id];
186 volatile unsigned long * const base = desc->base;
187 unsigned long imr;
188
189 if (id >= desc->list->count)
190 return;
191
192 int oldlevel = disable_irq_save();
193
194 /* Remove bit from mask */
195 imr = base[GPIO_IMR_I] & ~(1ul << event->line);
196
197 /* Mask the line */
198 base[GPIO_IMR_I] = imr;
199
200 if (imr == 0)
201 {
202 /* No events remain enabled */
203 avic_disable_int(desc->ints);
204 }
205
206 restore_irq(oldlevel);
207}
diff --git a/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.h b/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.h
new file mode 100644
index 0000000000..a197558ad4
--- /dev/null
+++ b/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.h
@@ -0,0 +1,77 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2008 by Michael Sevakis
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#ifndef _GPIO_IMX31_H_
20#define _GPIO_IMX31_H_
21
22#include "gpio-target.h"
23
24#define USE_GPIO1_EVENTS (1 << 0)
25#define USE_GPIO2_EVENTS (1 << 1)
26#define USE_GPIO3_EVENTS (1 << 2)
27
28enum gpio_module_number
29{
30 __GPIO_NUM_START = -1,
31#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
32 GPIO1_NUM,
33#endif
34#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
35 GPIO2_NUM,
36#endif
37#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
38 GPIO3_NUM,
39#endif
40 GPIO_NUM_GPIO,
41};
42
43/* Possible values for gpio interrupt line config */
44enum gpio_int_sense_enum
45{
46 GPIO_SENSE_LOW_LEVEL = 0, /* High-level sensitive */
47 GPIO_SENSE_HIGH_LEVEL, /* Low-level sensitive */
48 GPIO_SENSE_RISING, /* Rising-edge sensitive */
49 GPIO_SENSE_FALLING, /* Falling-edge sensitive */
50};
51
52#define GPIO_SENSE_CONFIG_MASK 0x3
53
54/* Pending events will be called in array order */
55
56/* Describes a single event for a pin */
57struct gpio_event
58{
59 int line; /* Line number (0-31) */
60 enum gpio_int_sense_enum sense; /* Type of sense */
61 int (*callback)(void); /* Callback function (return nonzero
62 * to indicate this event was handled) */
63};
64
65/* Describes the events attached to a port */
66struct gpio_event_list
67{
68 int priority; /* Interrupt priority for this GPIO */
69 unsigned count; /* Count of events */
70 const struct gpio_event *events; /* List of events */
71};
72
73void gpio_init(void);
74bool gpio_enable_event(enum gpio_module_number gpio, unsigned id);
75void gpio_disable_event(enum gpio_module_number gpio, unsigned id);
76
77#endif /* _GPIO_IMX31_H_ */
diff --git a/firmware/target/arm/imx31/gigabeat-s/gpio-target.h b/firmware/target/arm/imx31/gigabeat-s/gpio-target.h
new file mode 100644
index 0000000000..46e43af28d
--- /dev/null
+++ b/firmware/target/arm/imx31/gigabeat-s/gpio-target.h
@@ -0,0 +1,31 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2008 by Michael Sevakis
11 *
12 * Gigabeat S GPIO interrupt event descriptions header
13 *
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#ifndef GPIO_TARGET_H
22#define GPIO_TARGET_H
23
24#define GPIO_EVENT_MASK (USE_GPIO1_EVENTS)
25
26#define MC13783_GPIO_NUM GPIO1_NUM
27#define MC13783_GPIO_ISR GPIO1_ISR
28#define MC13783_GPIO_LINE 31
29#define MC13783_EVENT_ID 0
30
31#endif /* GPIO_TARGET_H */
diff --git a/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c b/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c
index 3af8f35f69..a04cd7f893 100644
--- a/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c
@@ -19,10 +19,13 @@
19#include "system.h" 19#include "system.h"
20#include "cpu.h" 20#include "cpu.h"
21#include "spi-imx31.h" 21#include "spi-imx31.h"
22#include "gpio-imx31.h"
22#include "mc13783.h" 23#include "mc13783.h"
23#include "debug.h" 24#include "debug.h"
24#include "kernel.h" 25#include "kernel.h"
25 26
27#include "button-target.h"
28
26/* This is all based on communicating with the MC13783 PMU which is on 29/* This is all based on communicating with the MC13783 PMU which is on
27 * CSPI2 with the chip select at 0. The LCD controller resides on 30 * CSPI2 with the chip select at 0. The LCD controller resides on
28 * CSPI3 cs1, but we have no idea how to communicate to it */ 31 * CSPI3 cs1, but we have no idea how to communicate to it */
@@ -43,17 +46,68 @@ static int mc13783_thread_stack[DEFAULT_STACK_SIZE/sizeof(int)];
43static const char *mc13783_thread_name = "pmic"; 46static const char *mc13783_thread_name = "pmic";
44static struct wakeup mc13783_wake; 47static struct wakeup mc13783_wake;
45 48
49/* The next two functions are rather target-specific but they'll just be left
50 * here for the moment */
46static __attribute__((noreturn)) void mc13783_interrupt_thread(void) 51static __attribute__((noreturn)) void mc13783_interrupt_thread(void)
47{ 52{
53 const unsigned char status_regs[2] =
54 {
55 MC13783_INTERRUPT_STATUS0,
56 MC13783_INTERRUPT_STATUS1,
57 };
58 uint32_t pending[2];
59 uint32_t value;
60
61 mc13783_read_regset(status_regs, pending, 2);
62 mc13783_write_regset(status_regs, pending, 2);
63
64 gpio_enable_event(MC13783_GPIO_NUM, MC13783_EVENT_ID);
65
66 /* Check initial states */
67 value = mc13783_read(MC13783_INTERRUPT_SENSE1);
68 button_power_set_state((value & MC13783_ON1B) == 0);
69 set_headphones_inserted((value & MC13783_ON2B) == 0);
70
71 /* Enable desired PMIC interrupts */
72 mc13783_clear(MC13783_INTERRUPT_MASK1, MC13783_ON1B | MC13783_ON2B);
73
48 while (1) 74 while (1)
49 { 75 {
50 wakeup_wait(&mc13783_wake, TIMEOUT_BLOCK); 76 wakeup_wait(&mc13783_wake, TIMEOUT_BLOCK);
77
78 mc13783_read_regset(status_regs, pending, 2);
79 mc13783_write_regset(status_regs, pending, 2);
80
81#if 0
82 if (pending[0])
83 {
84 /* Handle ...PENDING0 */
85 }
86#endif
87
88 if (pending[1])
89 {
90 /* Handle ...PENDING1 */
91 if (pending[1] & (MC13783_ON1B | MC13783_ON2B))
92 {
93 value = mc13783_read(MC13783_INTERRUPT_SENSE1);
94
95 if (pending[1] & MC13783_ON1B)
96 button_power_set_state((value & MC13783_ON1B) == 0);
97
98 if (pending[1] & MC13783_ON2B)
99 set_headphones_inserted((value & MC13783_ON2B) == 0);
100 }
101 }
51 } 102 }
52} 103}
53 104
54static __attribute__((interrupt("IRQ"))) void mc13783_interrupt(void) 105/* GPIO interrupt handler for mc13783 */
106int mc13783_event(void)
55{ 107{
108 MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE);
56 wakeup_signal(&mc13783_wake); 109 wakeup_signal(&mc13783_wake);
110 return 1; /* Yes, it's handled */
57} 111}
58 112
59void mc13783_init(void) 113void mc13783_init(void)
@@ -64,25 +118,44 @@ void mc13783_init(void)
64 /* Enable the PMIC SPI module */ 118 /* Enable the PMIC SPI module */
65 spi_enable_module(&mc13783_spi); 119 spi_enable_module(&mc13783_spi);
66 120
121 /* Mask any PMIC interrupts for now - poll initial status in thread
122 * and enable them there */
123 mc13783_write(MC13783_INTERRUPT_MASK0, 0xffffff);
124 mc13783_write(MC13783_INTERRUPT_MASK1, 0xffffff);
125
126 MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE);
127
67 create_thread(mc13783_interrupt_thread, mc13783_thread_stack, 128 create_thread(mc13783_interrupt_thread, mc13783_thread_stack,
68 sizeof(mc13783_thread_stack), 0, mc13783_thread_name 129 sizeof(mc13783_thread_stack), 0, mc13783_thread_name
69 IF_PRIO(, PRIORITY_REALTIME) IF_COP(, CPU)); 130 IF_PRIO(, PRIORITY_REALTIME) IF_COP(, CPU));
70} 131}
71 132
72void mc13783_set(unsigned address, uint32_t bits) 133uint32_t mc13783_set(unsigned address, uint32_t bits)
73{ 134{
74 spi_lock(&mc13783_spi); 135 spi_lock(&mc13783_spi);
136
75 uint32_t data = mc13783_read(address); 137 uint32_t data = mc13783_read(address);
76 mc13783_write(address, data | bits); 138
139 if (data != (uint32_t)-1)
140 mc13783_write(address, data | bits);
141
77 spi_unlock(&mc13783_spi); 142 spi_unlock(&mc13783_spi);
143
144 return data;
78} 145}
79 146
80void mc13783_clear(unsigned address, uint32_t bits) 147uint32_t mc13783_clear(unsigned address, uint32_t bits)
81{ 148{
82 spi_lock(&mc13783_spi); 149 spi_lock(&mc13783_spi);
150
83 uint32_t data = mc13783_read(address); 151 uint32_t data = mc13783_read(address);
84 mc13783_write(address, data & ~bits); 152
153 if (data != (uint32_t)-1)
154 mc13783_write(address, data & ~bits);
155
85 spi_unlock(&mc13783_spi); 156 spi_unlock(&mc13783_spi);
157
158 return data;
86} 159}
87 160
88int mc13783_write(unsigned address, uint32_t data) 161int mc13783_write(unsigned address, uint32_t data)
@@ -108,7 +181,7 @@ int mc13783_write_multiple(unsigned start, const uint32_t *data, int count)
108{ 181{
109 int i; 182 int i;
110 struct spi_transfer xfer; 183 struct spi_transfer xfer;
111 uint32_t packets[64]; 184 uint32_t packets[MC13783_NUM_REGS];
112 185
113 if (start + count > MC13783_NUM_REGS) 186 if (start + count > MC13783_NUM_REGS)
114 return -1; 187 return -1;
@@ -129,6 +202,36 @@ int mc13783_write_multiple(unsigned start, const uint32_t *data, int count)
129 return count - xfer.count; 202 return count - xfer.count;
130} 203}
131 204
205int mc13783_write_regset(const unsigned char *regs, const uint32_t *data,
206 int count)
207{
208 int i;
209 struct spi_transfer xfer;
210 uint32_t packets[MC13783_NUM_REGS];
211
212 if (count > MC13783_NUM_REGS)
213 return -1;
214
215 for (i = 0; i < count; i++)
216 {
217 uint32_t reg = regs[i];
218
219 if (reg >= MC13783_NUM_REGS)
220 return -1;
221
222 packets[i] = (1 << 31) | (reg << 25) | (data[i] & 0xffffff);
223 }
224
225 xfer.txbuf = packets;
226 xfer.rxbuf = packets;
227 xfer.count = count;
228
229 if (!spi_transfer(&mc13783_spi, &xfer))
230 return -1;
231
232 return count - xfer.count;
233}
234
132uint32_t mc13783_read(unsigned address) 235uint32_t mc13783_read(unsigned address)
133{ 236{
134 uint32_t packet; 237 uint32_t packet;
@@ -146,25 +249,53 @@ uint32_t mc13783_read(unsigned address)
146 if (!spi_transfer(&mc13783_spi, &xfer)) 249 if (!spi_transfer(&mc13783_spi, &xfer))
147 return (uint32_t)-1; 250 return (uint32_t)-1;
148 251
149 return packet & 0xffffff; 252 return packet;
150} 253}
151 254
152int mc13783_read_multiple(unsigned start, uint32_t *buffer, int count) 255int mc13783_read_multiple(unsigned start, uint32_t *buffer, int count)
153{ 256{
154 int i; 257 int i;
155 uint32_t packets[64];
156 struct spi_transfer xfer; 258 struct spi_transfer xfer;
157 259
158 if (start + count > MC13783_NUM_REGS) 260 if (start + count > MC13783_NUM_REGS)
159 return -1; 261 return -1;
160 262
161 xfer.txbuf = packets; 263 xfer.txbuf = buffer;
162 xfer.rxbuf = buffer; 264 xfer.rxbuf = buffer;
163 xfer.count = count; 265 xfer.count = count;
164 266
165 /* Prepare TX payload */ 267 /* Prepare TX payload */
166 for (i = 0; i < count; i++, start++) 268 for (i = 0; i < count; i++, start++)
167 packets[i] = start << 25; 269 buffer[i] = start << 25;
270
271 if (!spi_transfer(&mc13783_spi, &xfer))
272 return -1;
273
274 return count - xfer.count;
275}
276
277int mc13783_read_regset(const unsigned char *regs, uint32_t *buffer,
278 int count)
279{
280 int i;
281 struct spi_transfer xfer;
282
283 if (count > MC13783_NUM_REGS)
284 return -1;
285
286 for (i = 0; i < count; i++)
287 {
288 unsigned reg = regs[i];
289
290 if (reg >= MC13783_NUM_REGS)
291 return -1;
292
293 buffer[i] = reg << 25;
294 }
295
296 xfer.txbuf = buffer;
297 xfer.rxbuf = buffer;
298 xfer.count = count;
168 299
169 if (!spi_transfer(&mc13783_spi, &xfer)) 300 if (!spi_transfer(&mc13783_spi, &xfer))
170 return -1; 301 return -1;
diff --git a/firmware/target/arm/imx31/gigabeat-s/power-imx31.c b/firmware/target/arm/imx31/gigabeat-s/power-imx31.c
index c739a19cba..f57c55a70b 100644
--- a/firmware/target/arm/imx31/gigabeat-s/power-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/power-imx31.c
@@ -17,14 +17,12 @@
17 * 17 *
18 ****************************************************************************/ 18 ****************************************************************************/
19#include "config.h" 19#include "config.h"
20#include "cpu.h"
21#include <stdbool.h>
22#include "kernel.h"
23#include "system.h" 20#include "system.h"
24#include "power.h" 21#include "power.h"
25#include "pcf50606.h"
26#include "backlight.h" 22#include "backlight.h"
27#include "backlight-target.h" 23#include "backlight-target.h"
24#include "avic-imx31.h"
25#include "mc13783.h"
28 26
29#ifndef SIMULATOR 27#ifndef SIMULATOR
30 28
@@ -54,6 +52,10 @@ bool ide_powered(void)
54 52
55void power_off(void) 53void power_off(void)
56{ 54{
55 mc13783_set(MC13783_POWER_CONTROL0, MC13783_USEROFFSPI);
56
57 disable_interrupt(IRQ_FIQ_STATUS);
58 while (1);
57} 59}
58 60
59#else /* SIMULATOR */ 61#else /* SIMULATOR */
diff --git a/firmware/target/arm/imx31/gigabeat-s/system-imx31.c b/firmware/target/arm/imx31/gigabeat-s/system-imx31.c
index bd7999558b..da5026a292 100644
--- a/firmware/target/arm/imx31/gigabeat-s/system-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/system-imx31.c
@@ -2,6 +2,7 @@
2#include "system.h" 2#include "system.h"
3#include "panic.h" 3#include "panic.h"
4#include "avic-imx31.h" 4#include "avic-imx31.h"
5#include "gpio-imx31.h"
5#include "mmu-imx31.h" 6#include "mmu-imx31.h"
6#include "system-target.h" 7#include "system-target.h"
7#include "lcd.h" 8#include "lcd.h"
@@ -23,6 +24,7 @@ void system_init(void)
23 /* MCR WFI enables wait mode */ 24 /* MCR WFI enables wait mode */
24 CLKCTL_CCMR &= ~(3 << 14); 25 CLKCTL_CCMR &= ~(3 << 14);
25 avic_init(); 26 avic_init();
27 gpio_init();
26} 28}
27 29
28#ifdef BOOTLOADER 30#ifdef BOOTLOADER