summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx31/gigabeat-s
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/imx31/gigabeat-s')
-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
11 files changed, 545 insertions, 19 deletions
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