diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2008-05-21 08:42:11 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2008-05-21 08:42:11 +0000 |
commit | a9c20f5789c13b486d217024a020f9d6163e2d51 (patch) | |
tree | 5da52ca9cc7a28ba21ced042cb739e6160d5f87b /firmware | |
parent | 5f796087b009fee1ae60904b0355cc7febe3330f (diff) | |
download | rockbox-a9c20f5789c13b486d217024a020f9d6163e2d51.tar.gz rockbox-a9c20f5789c13b486d217024a020f9d6163e2d51.zip |
Gigabeat S:
1) Rework event handling and static registration mechanism. No target-
specific code in mc13783 driver. GPIO event driver interfaces more
cleanly.
2) Somewhat related - enable thread priority for bootloader which is
desireable here (ffs is used for GPIO event enabling anyway and that
goes along with priority).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17593 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
19 files changed, 433 insertions, 225 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES index bbdd0bc5a2..88e48bb226 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -679,12 +679,13 @@ target/arm/imx31/gigabeat-s/backlight-imx31.c | |||
679 | target/arm/imx31/gigabeat-s/button-imx31.c | 679 | target/arm/imx31/gigabeat-s/button-imx31.c |
680 | target/arm/imx31/gigabeat-s/clkctl-imx31.c | 680 | target/arm/imx31/gigabeat-s/clkctl-imx31.c |
681 | target/arm/imx31/gigabeat-s/dma_start.c | 681 | target/arm/imx31/gigabeat-s/dma_start.c |
682 | target/arm/imx31/gigabeat-s/gpio-imx31.c | ||
683 | target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c | 682 | target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c |
683 | target/arm/imx31/gigabeat-s/gpio-imx31.c | ||
684 | target/arm/imx31/gigabeat-s/kernel-imx31.c | 684 | target/arm/imx31/gigabeat-s/kernel-imx31.c |
685 | target/arm/imx31/gigabeat-s/i2c-imx31.c | 685 | target/arm/imx31/gigabeat-s/i2c-imx31.c |
686 | target/arm/imx31/gigabeat-s/i2s-imx31.c | 686 | target/arm/imx31/gigabeat-s/i2s-imx31.c |
687 | target/arm/imx31/gigabeat-s/lcd-imx31.c | 687 | target/arm/imx31/gigabeat-s/lcd-imx31.c |
688 | target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c | ||
688 | target/arm/imx31/gigabeat-s/mc13783-imx31.c | 689 | target/arm/imx31/gigabeat-s/mc13783-imx31.c |
689 | target/arm/imx31/gigabeat-s/mmu-imx31.c | 690 | target/arm/imx31/gigabeat-s/mmu-imx31.c |
690 | target/arm/imx31/gigabeat-s/power-imx31.c | 691 | target/arm/imx31/gigabeat-s/power-imx31.c |
diff --git a/firmware/drivers/rtc/rtc_mc13783.c b/firmware/drivers/rtc/rtc_mc13783.c index 9d2c50cf11..325a496646 100644 --- a/firmware/drivers/rtc/rtc_mc13783.c +++ b/firmware/drivers/rtc/rtc_mc13783.c | |||
@@ -67,11 +67,6 @@ enum rtc_registers_indexes | |||
67 | /* was it an alarm that triggered power on ? */ | 67 | /* was it an alarm that triggered power on ? */ |
68 | static bool alarm_start = false; | 68 | static bool alarm_start = false; |
69 | 69 | ||
70 | void mc13783_alarm_start(void) | ||
71 | { | ||
72 | alarm_start = true; | ||
73 | } | ||
74 | |||
75 | static const unsigned char rtc_registers[RTC_NUM_REGS] = | 70 | static const unsigned char rtc_registers[RTC_NUM_REGS] = |
76 | { | 71 | { |
77 | [RTC_REG_TIME] = MC13783_RTC_TIME, | 72 | [RTC_REG_TIME] = MC13783_RTC_TIME, |
@@ -122,7 +117,12 @@ static int is_leap_year(int y) | |||
122 | /** Public APIs **/ | 117 | /** Public APIs **/ |
123 | void rtc_init(void) | 118 | void rtc_init(void) |
124 | { | 119 | { |
125 | /* Nothing to do */ | 120 | /* only needs to be polled on startup */ |
121 | if (mc13783_read(MC13783_INTERRUPT_STATUS1) & MC13783_TODAI) | ||
122 | { | ||
123 | alarm_start = true; | ||
124 | mc13783_write(MC13783_INTERRUPT_STATUS1, MC13783_TODAI); | ||
125 | } | ||
126 | } | 126 | } |
127 | 127 | ||
128 | int rtc_read_datetime(unsigned char* buf) | 128 | int rtc_read_datetime(unsigned char* buf) |
@@ -264,7 +264,9 @@ bool rtc_enable_alarm(bool enable) | |||
264 | bool rtc_check_alarm_started(bool release_alarm) | 264 | bool rtc_check_alarm_started(bool release_alarm) |
265 | { | 265 | { |
266 | bool rc = alarm_start; | 266 | bool rc = alarm_start; |
267 | alarm_start &= ~release_alarm; | 267 | |
268 | if (release_alarm) | ||
269 | alarm_start = false; | ||
268 | 270 | ||
269 | return rc; | 271 | return rc; |
270 | } | 272 | } |
diff --git a/firmware/export/config-gigabeat-s.h b/firmware/export/config-gigabeat-s.h index a0c05dad45..cafb202ebe 100644 --- a/firmware/export/config-gigabeat-s.h +++ b/firmware/export/config-gigabeat-s.h | |||
@@ -97,6 +97,7 @@ | |||
97 | /* Define the bitmask of modules used */ | 97 | /* Define the bitmask of modules used */ |
98 | #define SPI_MODULE_MASK (USE_CSPI2_MODULE) | 98 | #define SPI_MODULE_MASK (USE_CSPI2_MODULE) |
99 | #define I2C_MODULE_MASK (USE_I2C1_MODULE) | 99 | #define I2C_MODULE_MASK (USE_I2C1_MODULE) |
100 | #define GPIO_EVENT_MASK (USE_GPIO1_EVENTS) | ||
100 | 101 | ||
101 | /* Define this if target has an additional number of threads specific to it */ | 102 | /* Define this if target has an additional number of threads specific to it */ |
102 | #define TARGET_EXTRA_THREADS 1 | 103 | #define TARGET_EXTRA_THREADS 1 |
diff --git a/firmware/export/config.h b/firmware/export/config.h index c200355872..c7e204c5df 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h | |||
@@ -341,7 +341,14 @@ | |||
341 | #endif | 341 | #endif |
342 | 342 | ||
343 | #if (CONFIG_CODEC == SWCODEC) | 343 | #if (CONFIG_CODEC == SWCODEC) |
344 | #ifndef BOOTLOADER | 344 | #ifdef BOOTLOADER |
345 | |||
346 | #if CONFIG_CPU == IMX31L | ||
347 | /* Priority in bootloader is wanted */ | ||
348 | #define HAVE_PRIORITY_SCHEDULING | ||
349 | #endif | ||
350 | |||
351 | #else /* !BOOTLOADER */ | ||
345 | 352 | ||
346 | #define HAVE_EXTENDED_MESSAGING_AND_NAME | 353 | #define HAVE_EXTENDED_MESSAGING_AND_NAME |
347 | 354 | ||
diff --git a/firmware/export/mc13783.h b/firmware/export/mc13783.h index 6ed1cb46be..1f6fee8c44 100644 --- a/firmware/export/mc13783.h +++ b/firmware/export/mc13783.h | |||
@@ -1270,6 +1270,9 @@ enum mc13783_regs_enum | |||
1270 | #define MC13783_TC3PERIODr(x) (((x) & MC13783_TC3PERIOD) >> 21) | 1270 | #define MC13783_TC3PERIODr(x) (((x) & MC13783_TC3PERIOD) >> 21) |
1271 | #define MC13783_TC3TRIODE (0x1 << 23) | 1271 | #define MC13783_TC3TRIODE (0x1 << 23) |
1272 | 1272 | ||
1273 | /* For event enum values which are target-defined */ | ||
1274 | #include "mc13783-target.h" | ||
1275 | |||
1273 | void mc13783_init(void); | 1276 | void mc13783_init(void); |
1274 | void mc13783_close(void); | 1277 | void mc13783_close(void); |
1275 | uint32_t mc13783_set(unsigned address, uint32_t bits); | 1278 | uint32_t mc13783_set(unsigned address, uint32_t bits); |
@@ -1281,6 +1284,28 @@ int mc13783_write_regset(const unsigned char *regs, const uint32_t *data, int co | |||
1281 | uint32_t mc13783_read(unsigned address); | 1284 | uint32_t mc13783_read(unsigned address); |
1282 | int mc13783_read_multiple(unsigned start, uint32_t *buffer, int count); | 1285 | int mc13783_read_multiple(unsigned start, uint32_t *buffer, int count); |
1283 | int mc13783_read_regset(const unsigned char *regs, uint32_t *buffer, int count); | 1286 | int mc13783_read_regset(const unsigned char *regs, uint32_t *buffer, int count); |
1284 | void mc13783_alarm_start(void); | 1287 | |
1288 | /* Statically-registered event enable/disable */ | ||
1289 | enum mc13783_event_sets | ||
1290 | { | ||
1291 | MC13783_EVENT_SET0 = 0, | ||
1292 | MC13783_EVENT_SET1 = 1, | ||
1293 | }; | ||
1294 | |||
1295 | struct mc13783_event | ||
1296 | { | ||
1297 | enum mc13783_event_sets set : 8; | ||
1298 | uint32_t mask : 24; | ||
1299 | void (*callback)(void); | ||
1300 | }; | ||
1301 | |||
1302 | struct mc13783_event_list | ||
1303 | { | ||
1304 | unsigned count; | ||
1305 | const struct mc13783_event *events; | ||
1306 | }; | ||
1307 | |||
1308 | bool mc13783_enable_event(enum mc13783_event_ids event); | ||
1309 | void mc13783_disable_event(enum mc13783_event_ids event); | ||
1285 | 1310 | ||
1286 | #endif /* _MC13783_H_ */ | 1311 | #endif /* _MC13783_H_ */ |
diff --git a/firmware/target/arm/imx31/gigabeat-s/adc-imx31.c b/firmware/target/arm/imx31/gigabeat-s/adc-imx31.c index d26d708da1..2f4e45c3b1 100644 --- a/firmware/target/arm/imx31/gigabeat-s/adc-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/adc-imx31.c | |||
@@ -77,11 +77,11 @@ unsigned short adc_read(int channel) | |||
77 | 77 | ||
78 | mutex_unlock(&adc_mtx); | 78 | mutex_unlock(&adc_mtx); |
79 | 79 | ||
80 | /* Channels 0-3/8-11 in ADD1, 0-4/12-15 in ADD2 */ | 80 | /* Channels 0-3/8-11 in ADD1, 4-7/12-15 in ADD2 */ |
81 | return (channel & 4) ? MC13783_ADD2r(data) : MC13783_ADD1r(data); | 81 | return (channel & 4) ? MC13783_ADD2r(data) : MC13783_ADD1r(data); |
82 | } | 82 | } |
83 | 83 | ||
84 | /* Called when conversion is complete */ | 84 | /* Called by mc13783 interrupt thread when conversion is complete */ |
85 | void adc_done(void) | 85 | void adc_done(void) |
86 | { | 86 | { |
87 | wakeup_signal(&adc_wake); | 87 | wakeup_signal(&adc_wake); |
@@ -100,7 +100,8 @@ void adc_init(void) | |||
100 | MC13783_RTHEN | MC13783_CHRGICON); | 100 | MC13783_RTHEN | MC13783_CHRGICON); |
101 | /* Enable ADC, set multi-channel mode */ | 101 | /* Enable ADC, set multi-channel mode */ |
102 | mc13783_write(MC13783_ADC1, MC13783_ADEN); | 102 | mc13783_write(MC13783_ADC1, MC13783_ADEN); |
103 | /* Enable the ADCDONE interrupt - notifications are dispatched by | 103 | |
104 | * event handler. */ | 104 | /* Enable ADCDONE event */ |
105 | mc13783_clear(MC13783_INTERRUPT_MASK0, MC13783_ADCDONEM); | 105 | mc13783_write(MC13783_INTERRUPT_STATUS0, MC13783_ADCDONEI); |
106 | mc13783_enable_event(MC13783_ADCDONE_EVENT); | ||
106 | } | 107 | } |
diff --git a/firmware/target/arm/imx31/gigabeat-s/button-imx31.c b/firmware/target/arm/imx31/gigabeat-s/button-imx31.c index 746883d010..ad1e2b7e49 100644 --- a/firmware/target/arm/imx31/gigabeat-s/button-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/button-imx31.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include "backlight-target.h" | 26 | #include "backlight-target.h" |
27 | #include "avic-imx31.h" | 27 | #include "avic-imx31.h" |
28 | #include "clkctl-imx31.h" | 28 | #include "clkctl-imx31.h" |
29 | #include "mc13783.h" | ||
29 | 30 | ||
30 | /* Most code in here is taken from the Linux BSP provided by Freescale | 31 | /* Most code in here is taken from the Linux BSP provided by Freescale |
31 | * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. */ | 32 | * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. */ |
@@ -119,56 +120,6 @@ static __attribute__((interrupt("IRQ"))) void KPP_HANDLER(void) | |||
119 | int_btn = button; | 120 | int_btn = button; |
120 | } | 121 | } |
121 | 122 | ||
122 | void button_init_device(void) | ||
123 | { | ||
124 | #ifdef BOOTLOADER | ||
125 | /* Can be called more than once in the bootloader */ | ||
126 | if (initialized) | ||
127 | return; | ||
128 | |||
129 | initialized = true; | ||
130 | #endif | ||
131 | |||
132 | /* Enable keypad clock */ | ||
133 | imx31_clkctl_module_clock_gating(CG_KPP, CGM_ON_ALL); | ||
134 | |||
135 | /* 1. Enable number of rows in keypad (KPCR[4:0]) | ||
136 | * | ||
137 | * Configure the rows/cols in KPP | ||
138 | * LSB nybble in KPP is for 5 rows | ||
139 | * MSB nybble in KPP is for 3 cols */ | ||
140 | KPP_KPCR |= 0x1f; | ||
141 | |||
142 | /* 2. Write 0's to KPDR[10:8] */ | ||
143 | KPP_KPDR &= ~(0x7 << 8); | ||
144 | |||
145 | /* 3. Configure the keypad columns as open-drain (KPCR[10:8]). */ | ||
146 | KPP_KPCR |= (0x7 << 8); | ||
147 | |||
148 | /* 4. Configure columns as output, rows as input (KDDR[10:8,4:0]) */ | ||
149 | KPP_KDDR = (KPP_KDDR | (0x7 << 8)) & ~0x1f; | ||
150 | |||
151 | /* 5. Clear the KPKD Status Flag and Synchronizer chain. | ||
152 | * 6. Set the KDIE control bit bit. */ | ||
153 | KPP_KPSR = KPP_KPSR_KDIE | KPP_KPSR_KRSS | KPP_KPSR_KDSC | KPP_KPSR_KPKD; | ||
154 | |||
155 | /* KPP IRQ at priority 3 */ | ||
156 | avic_enable_int(KPP, IRQ, 3, KPP_HANDLER); | ||
157 | } | ||
158 | |||
159 | #ifdef BUTTON_DRIVER_CLOSE | ||
160 | void button_close_device(void) | ||
161 | { | ||
162 | int oldlevel = disable_irq_save(); | ||
163 | |||
164 | avic_disable_int(KPP); | ||
165 | KPP_KPSR &= ~(KPP_KPSR_KRIE | KPP_KPSR_KDIE); | ||
166 | int_btn = BUTTON_NONE; | ||
167 | |||
168 | restore_irq(oldlevel); | ||
169 | } | ||
170 | #endif /* BUTTON_DRIVER_CLOSE */ | ||
171 | |||
172 | bool button_hold(void) | 123 | bool button_hold(void) |
173 | { | 124 | { |
174 | return _button_hold(); | 125 | return _button_hold(); |
@@ -199,8 +150,11 @@ int button_read_device(void) | |||
199 | } | 150 | } |
200 | 151 | ||
201 | /* This is called from the mc13783 interrupt thread */ | 152 | /* This is called from the mc13783 interrupt thread */ |
202 | void button_power_set_state(bool pressed) | 153 | void button_power_event(void) |
203 | { | 154 | { |
155 | bool pressed = | ||
156 | (mc13783_read(MC13783_INTERRUPT_SENSE1) & MC13783_ONOFD1S) == 0; | ||
157 | |||
204 | /* Prevent KPP_HANDLER from changing things */ | 158 | /* Prevent KPP_HANDLER from changing things */ |
205 | int oldlevel = disable_irq_save(); | 159 | int oldlevel = disable_irq_save(); |
206 | 160 | ||
@@ -218,16 +172,73 @@ void button_power_set_state(bool pressed) | |||
218 | 172 | ||
219 | #ifdef HAVE_HEADPHONE_DETECTION | 173 | #ifdef HAVE_HEADPHONE_DETECTION |
220 | /* This is called from the mc13783 interrupt thread */ | 174 | /* This is called from the mc13783 interrupt thread */ |
221 | void set_headphones_inserted(bool inserted) | 175 | void headphone_detect_event(void) |
222 | { | 176 | { |
223 | headphones_detect = inserted; | 177 | /* FIXME: Not really the correct method */ |
178 | headphones_detect = | ||
179 | (mc13783_read(MC13783_INTERRUPT_SENSE1) & MC13783_ONOFD2S) == 0; | ||
224 | } | 180 | } |
225 | 181 | ||
226 | /* This is called from the mc13783 interrupt thread */ | ||
227 | /* TODO: Just do a post to the button queue directly - implement the | ||
228 | * appropriate variant in the driver. */ | ||
229 | bool headphones_inserted(void) | 182 | bool headphones_inserted(void) |
230 | { | 183 | { |
231 | return headphones_detect; | 184 | return headphones_detect; |
232 | } | 185 | } |
233 | #endif /* HAVE_HEADPHONE_DETECTION */ | 186 | #endif /* HAVE_HEADPHONE_DETECTION */ |
187 | |||
188 | void button_init_device(void) | ||
189 | { | ||
190 | #ifdef BOOTLOADER | ||
191 | /* Can be called more than once in the bootloader */ | ||
192 | if (initialized) | ||
193 | return; | ||
194 | |||
195 | initialized = true; | ||
196 | #endif | ||
197 | |||
198 | /* Enable keypad clock */ | ||
199 | imx31_clkctl_module_clock_gating(CG_KPP, CGM_ON_ALL); | ||
200 | |||
201 | /* 1. Enable number of rows in keypad (KPCR[4:0]) | ||
202 | * | ||
203 | * Configure the rows/cols in KPP | ||
204 | * LSB nybble in KPP is for 5 rows | ||
205 | * MSB nybble in KPP is for 3 cols */ | ||
206 | KPP_KPCR |= 0x1f; | ||
207 | |||
208 | /* 2. Write 0's to KPDR[10:8] */ | ||
209 | KPP_KPDR &= ~(0x7 << 8); | ||
210 | |||
211 | /* 3. Configure the keypad columns as open-drain (KPCR[10:8]). */ | ||
212 | KPP_KPCR |= (0x7 << 8); | ||
213 | |||
214 | /* 4. Configure columns as output, rows as input (KDDR[10:8,4:0]) */ | ||
215 | KPP_KDDR = (KPP_KDDR | (0x7 << 8)) & ~0x1f; | ||
216 | |||
217 | /* 5. Clear the KPKD Status Flag and Synchronizer chain. | ||
218 | * 6. Set the KDIE control bit bit. */ | ||
219 | KPP_KPSR = KPP_KPSR_KDIE | KPP_KPSR_KRSS | KPP_KPSR_KDSC | KPP_KPSR_KPKD; | ||
220 | |||
221 | /* KPP IRQ at priority 3 */ | ||
222 | avic_enable_int(KPP, IRQ, 3, KPP_HANDLER); | ||
223 | |||
224 | button_power_event(); | ||
225 | mc13783_enable_event(MC13783_ONOFD1_EVENT); | ||
226 | |||
227 | #ifdef HAVE_HEADPHONE_DETECTION | ||
228 | headphone_detect_event(); | ||
229 | mc13783_enable_event(MC13783_ONOFD2_EVENT); | ||
230 | #endif | ||
231 | } | ||
232 | |||
233 | #ifdef BUTTON_DRIVER_CLOSE | ||
234 | void button_close_device(void) | ||
235 | { | ||
236 | int oldlevel = disable_irq_save(); | ||
237 | |||
238 | avic_disable_int(KPP); | ||
239 | KPP_KPSR &= ~(KPP_KPSR_KRIE | KPP_KPSR_KDIE); | ||
240 | int_btn = BUTTON_NONE; | ||
241 | |||
242 | restore_irq(oldlevel); | ||
243 | } | ||
244 | #endif /* BUTTON_DRIVER_CLOSE */ | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/button-target.h b/firmware/target/arm/imx31/gigabeat-s/button-target.h index 61d33f8e70..28c14f358c 100644 --- a/firmware/target/arm/imx31/gigabeat-s/button-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/button-target.h | |||
@@ -32,8 +32,8 @@ bool button_hold(void); | |||
32 | void button_init_device(void); | 32 | void button_init_device(void); |
33 | void button_close_device(void); | 33 | void button_close_device(void); |
34 | int button_read_device(void); | 34 | int button_read_device(void); |
35 | void button_power_set_state(bool pressed); | 35 | void button_power_event(void); |
36 | void set_headphones_inserted(bool inserted); | 36 | void headphone_detect_event(void); |
37 | bool headphones_inserted(void); | 37 | bool headphones_inserted(void); |
38 | 38 | ||
39 | /* Toshiba Gigabeat S-specific button codes */ | 39 | /* Toshiba Gigabeat S-specific button codes */ |
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 cfbb7fcc4c..64d156407e 100644 --- a/firmware/target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c | |||
@@ -22,18 +22,23 @@ | |||
22 | #include "system.h" | 22 | #include "system.h" |
23 | #include "gpio-imx31.h" | 23 | #include "gpio-imx31.h" |
24 | 24 | ||
25 | extern int mc13783_event(void); | 25 | /* Gigabeat S definitions for static GPIO event registration */ |
26 | 26 | ||
27 | static const struct gpio_event gpio1_events = | 27 | /* Describes single events for each GPIO1 pin */ |
28 | static const struct gpio_event gpio1_events[] = | ||
28 | { | 29 | { |
29 | .line = MC13783_GPIO_LINE, | 30 | [MC13783_EVENT_ID-GPIO1_EVENT_FIRST] = |
30 | .sense = GPIO_SENSE_RISING, | 31 | { |
31 | .callback = mc13783_event, | 32 | .mask = 1 << MC13783_GPIO_LINE, |
33 | .sense = GPIO_SENSE_RISING, | ||
34 | .callback = mc13783_event, | ||
35 | } | ||
32 | }; | 36 | }; |
33 | 37 | ||
38 | /* Describes the events attached to GPIO1 port */ | ||
34 | const struct gpio_event_list gpio1_event_list = | 39 | const struct gpio_event_list gpio1_event_list = |
35 | { | 40 | { |
36 | .priority = 7, | 41 | .ints_priority = 7, |
37 | .count = 1, | 42 | .count = ARRAYLEN(gpio1_events), |
38 | .events = &gpio1_events, | 43 | .events = gpio1_events, |
39 | }; | 44 | }; |
diff --git a/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.c b/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.c index 0b76b84d36..2a83b5ca73 100644 --- a/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.c | |||
@@ -73,29 +73,38 @@ static struct gpio_module_descriptor | |||
73 | #endif | 73 | #endif |
74 | }; | 74 | }; |
75 | 75 | ||
76 | static void gpio_call_events(enum gpio_module_number gpio) | 76 | static void gpio_call_events(const struct gpio_module_descriptor * const desc) |
77 | { | 77 | { |
78 | const struct gpio_module_descriptor * const desc = &gpio_descs[gpio]; | ||
79 | const struct gpio_event_list * const list = desc->list; | 78 | const struct gpio_event_list * const list = desc->list; |
80 | struct gpio_map * const base = desc->base; | 79 | struct gpio_map * const base = desc->base; |
81 | unsigned i; | 80 | const struct gpio_event * event, *event_last; |
82 | 81 | ||
83 | /* Intersect pending and unmasked bits */ | 82 | /* Intersect pending and unmasked bits */ |
84 | uint32_t pending = base->isr & base->imr; | 83 | uint32_t pnd = base->isr & base->imr; |
84 | |||
85 | event = list->events; | ||
86 | event_last = event + list->count; | ||
85 | 87 | ||
86 | /* Call each event handler in order */ | 88 | /* Call each event handler in order */ |
87 | for (i = 0; i < list->count; i++) | 89 | /* .count is surely expected to be > 0 */ |
90 | do | ||
88 | { | 91 | { |
89 | const struct gpio_event * const event = &list->events[i]; | 92 | uint32_t mask = event->mask; |
90 | uint32_t bit = 1ul << event->line; | 93 | |
94 | if (pnd & mask) | ||
95 | { | ||
96 | event->callback(); | ||
97 | pnd &= ~mask; | ||
98 | } | ||
91 | 99 | ||
92 | if ((pending & bit) && event->callback()) | 100 | if (pnd == 0) |
93 | pending &= ~bit; | 101 | break; /* Teminate early if nothing more to service */ |
94 | } | 102 | } |
103 | while (++event < event_last); | ||
95 | 104 | ||
96 | if (pending != 0) | 105 | if (pnd != 0) |
97 | { | 106 | { |
98 | /* Wasn't handled */ | 107 | /* One or more weren't handled */ |
99 | UIE_VECTOR(); | 108 | UIE_VECTOR(); |
100 | } | 109 | } |
101 | } | 110 | } |
@@ -103,21 +112,21 @@ static void gpio_call_events(enum gpio_module_number gpio) | |||
103 | #if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) | 112 | #if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) |
104 | static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void) | 113 | static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void) |
105 | { | 114 | { |
106 | gpio_call_events(GPIO1_NUM); | 115 | gpio_call_events(&gpio_descs[GPIO1_NUM]); |
107 | } | 116 | } |
108 | #endif | 117 | #endif |
109 | 118 | ||
110 | #if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) | 119 | #if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) |
111 | static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void) | 120 | static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void) |
112 | { | 121 | { |
113 | gpio_call_events(GPIO2_NUM); | 122 | gpio_call_events(&gpio_descs[GPIO2_NUM]); |
114 | } | 123 | } |
115 | #endif | 124 | #endif |
116 | 125 | ||
117 | #if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) | 126 | #if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) |
118 | static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void) | 127 | static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void) |
119 | { | 128 | { |
120 | gpio_call_events(GPIO3_NUM); | 129 | gpio_call_events(&gpio_descs[GPIO3_NUM]); |
121 | } | 130 | } |
122 | #endif | 131 | #endif |
123 | 132 | ||
@@ -140,19 +149,16 @@ void gpio_init(void) | |||
140 | #endif | 149 | #endif |
141 | } | 150 | } |
142 | 151 | ||
143 | bool gpio_enable_event(enum gpio_module_number gpio, unsigned id) | 152 | bool gpio_enable_event(enum gpio_event_ids id) |
144 | { | 153 | { |
145 | const struct gpio_module_descriptor * const desc = &gpio_descs[gpio]; | 154 | const struct gpio_module_descriptor * const desc = &gpio_descs[id >> 5]; |
146 | const struct gpio_event * const event = &desc->list->events[id]; | 155 | const struct gpio_event * const event = &desc->list->events[id & 31]; |
147 | struct gpio_map * const base = desc->base; | 156 | struct gpio_map * const base = desc->base; |
148 | volatile uint32_t *icr; | 157 | volatile uint32_t *icr; |
149 | uint32_t mask; | 158 | uint32_t mask, line; |
150 | uint32_t imr; | 159 | uint32_t imr; |
151 | int shift; | 160 | int shift; |
152 | 161 | ||
153 | if (id >= desc->list->count) | ||
154 | return false; | ||
155 | |||
156 | int oldlevel = disable_irq_save(); | 162 | int oldlevel = disable_irq_save(); |
157 | 163 | ||
158 | imr = base->imr; | 164 | imr = base->imr; |
@@ -160,39 +166,37 @@ bool gpio_enable_event(enum gpio_module_number gpio, unsigned id) | |||
160 | if (imr == 0) | 166 | if (imr == 0) |
161 | { | 167 | { |
162 | /* First enabled interrupt for this GPIO */ | 168 | /* First enabled interrupt for this GPIO */ |
163 | avic_enable_int(desc->ints, IRQ, desc->list->priority, | 169 | avic_enable_int(desc->ints, IRQ, desc->list->ints_priority, |
164 | desc->handler); | 170 | desc->handler); |
165 | } | 171 | } |
166 | 172 | ||
167 | /* Set the line sense */ | 173 | /* Set the line sense */ |
168 | icr = &base->icr[event->line >> 4]; | 174 | line = find_first_set_bit(event->mask); |
169 | shift = (event->line & 15) << 1; | 175 | icr = &base->icr[line >> 4]; |
176 | shift = (line & 15) << 1; | ||
170 | mask = GPIO_SENSE_CONFIG_MASK << shift; | 177 | mask = GPIO_SENSE_CONFIG_MASK << shift; |
171 | 178 | ||
172 | *icr = (*icr & ~mask) | ((event->sense << shift) & mask); | 179 | *icr = (*icr & ~mask) | ((event->sense << shift) & mask); |
173 | 180 | ||
174 | /* Unmask the line */ | 181 | /* Unmask the line */ |
175 | base->imr = imr | (1ul << event->line); | 182 | base->imr = imr | event->mask; |
176 | 183 | ||
177 | restore_irq(oldlevel); | 184 | restore_irq(oldlevel); |
178 | 185 | ||
179 | return true; | 186 | return true; |
180 | } | 187 | } |
181 | 188 | ||
182 | void gpio_disable_event(enum gpio_module_number gpio, unsigned id) | 189 | void gpio_disable_event(enum gpio_event_ids id) |
183 | { | 190 | { |
184 | const struct gpio_module_descriptor * const desc = &gpio_descs[gpio]; | 191 | const struct gpio_module_descriptor * const desc = &gpio_descs[id >> 5]; |
185 | const struct gpio_event * const event = &desc->list->events[id]; | 192 | const struct gpio_event * const event = &desc->list->events[id & 31]; |
186 | struct gpio_map * const base = desc->base; | 193 | struct gpio_map * const base = desc->base; |
187 | uint32_t imr; | 194 | uint32_t imr; |
188 | 195 | ||
189 | if (id >= desc->list->count) | ||
190 | return; | ||
191 | |||
192 | int oldlevel = disable_irq_save(); | 196 | int oldlevel = disable_irq_save(); |
193 | 197 | ||
194 | /* Remove bit from mask */ | 198 | /* Remove bit from mask */ |
195 | imr = base->imr & ~(1ul << event->line); | 199 | imr = base->imr & ~event->mask; |
196 | 200 | ||
197 | /* Mask the line */ | 201 | /* Mask the line */ |
198 | base->imr = imr; | 202 | base->imr = imr; |
diff --git a/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.h b/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.h index 34d3e72f8e..c3c3e1f63b 100644 --- a/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.h +++ b/firmware/target/arm/imx31/gigabeat-s/gpio-imx31.h | |||
@@ -19,12 +19,12 @@ | |||
19 | #ifndef GPIO_IMX31_H | 19 | #ifndef GPIO_IMX31_H |
20 | #define GPIO_IMX31_H | 20 | #define GPIO_IMX31_H |
21 | 21 | ||
22 | #include "gpio-target.h" | 22 | /* Static registration mechanism for imx31 GPIO interrupts */ |
23 | |||
24 | #define USE_GPIO1_EVENTS (1 << 0) | 23 | #define USE_GPIO1_EVENTS (1 << 0) |
25 | #define USE_GPIO2_EVENTS (1 << 1) | 24 | #define USE_GPIO2_EVENTS (1 << 1) |
26 | #define USE_GPIO3_EVENTS (1 << 2) | 25 | #define USE_GPIO3_EVENTS (1 << 2) |
27 | 26 | ||
27 | /* Module indexes defined by which GPIO modules are used */ | ||
28 | enum gpio_module_number | 28 | enum gpio_module_number |
29 | { | 29 | { |
30 | __GPIO_NUM_START = -1, | 30 | __GPIO_NUM_START = -1, |
@@ -40,6 +40,22 @@ enum gpio_module_number | |||
40 | GPIO_NUM_GPIO, | 40 | GPIO_NUM_GPIO, |
41 | }; | 41 | }; |
42 | 42 | ||
43 | /* Module corresponding to the event ID is identified by range */ | ||
44 | enum gpio_event_bases | ||
45 | { | ||
46 | #if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) | ||
47 | GPIO1_EVENT_FIRST = 32*GPIO1_NUM, | ||
48 | #endif | ||
49 | #if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) | ||
50 | GPIO2_EVENT_FIRST = 32*GPIO2_NUM, | ||
51 | #endif | ||
52 | #if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) | ||
53 | GPIO3_EVENT_FIRST = 32*GPIO3_NUM, | ||
54 | #endif | ||
55 | }; | ||
56 | |||
57 | #include "gpio-target.h" | ||
58 | |||
43 | /* Possible values for gpio interrupt line config */ | 59 | /* Possible values for gpio interrupt line config */ |
44 | enum gpio_int_sense_enum | 60 | enum gpio_int_sense_enum |
45 | { | 61 | { |
@@ -54,35 +70,43 @@ enum gpio_int_sense_enum | |||
54 | /* Register map for each module */ | 70 | /* Register map for each module */ |
55 | struct gpio_map | 71 | struct gpio_map |
56 | { | 72 | { |
57 | volatile uint32_t dr; /* 00h */ | 73 | volatile uint32_t dr; /* 00h */ |
58 | volatile uint32_t gdir; /* 04h */ | 74 | volatile uint32_t gdir; /* 04h */ |
59 | volatile uint32_t psr; /* 08h */ | 75 | volatile uint32_t psr; /* 08h */ |
60 | volatile uint32_t icr[2]; /* 0Ch */ | 76 | union |
61 | volatile uint32_t imr; /* 14h */ | 77 | { |
62 | volatile uint32_t isr; /* 18h */ | 78 | struct |
79 | { | ||
80 | volatile uint32_t icr1; /* 0Ch */ | ||
81 | volatile uint32_t icr2; /* 10h */ | ||
82 | }; | ||
83 | volatile uint32_t icr[2]; /* 0Ch */ | ||
84 | }; | ||
85 | volatile uint32_t imr; /* 14h */ | ||
86 | volatile uint32_t isr; /* 18h */ | ||
63 | }; | 87 | }; |
64 | 88 | ||
65 | /* Pending events will be called in array order */ | 89 | /* Pending events will be called in array order which allows easy |
90 | * pioritization */ | ||
66 | 91 | ||
67 | /* Describes a single event for a pin */ | 92 | /* Describes a single event for a pin */ |
68 | struct gpio_event | 93 | struct gpio_event |
69 | { | 94 | { |
70 | int line; /* Line number (0-31) */ | 95 | uint32_t mask; /* mask: 1 << (0...31) */ |
71 | enum gpio_int_sense_enum sense; /* Type of sense */ | 96 | enum gpio_int_sense_enum sense; /* Type of sense */ |
72 | int (*callback)(void); /* Callback function (return nonzero | 97 | void (*callback)(void); /* Callback function */ |
73 | * to indicate this event was handled) */ | ||
74 | }; | 98 | }; |
75 | 99 | ||
76 | /* Describes the events attached to a port */ | 100 | /* Describes the events attached to a port */ |
77 | struct gpio_event_list | 101 | struct gpio_event_list |
78 | { | 102 | { |
79 | int priority; /* Interrupt priority for this GPIO */ | 103 | int ints_priority; /* Interrupt priority for this GPIO */ |
80 | unsigned count; /* Count of events */ | 104 | unsigned count; /* Count of events for the module */ |
81 | const struct gpio_event *events; /* List of events */ | 105 | const struct gpio_event *events; /* List of events */ |
82 | }; | 106 | }; |
83 | 107 | ||
84 | void gpio_init(void); | 108 | void gpio_init(void); |
85 | bool gpio_enable_event(enum gpio_module_number gpio, unsigned id); | 109 | bool gpio_enable_event(enum gpio_event_ids id); |
86 | void gpio_disable_event(enum gpio_module_number gpio, unsigned id); | 110 | void gpio_disable_event(enum gpio_event_ids id); |
87 | 111 | ||
88 | #endif /* GPIO_IMX31_H */ | 112 | #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 index 46e43af28d..797f9f4552 100644 --- a/firmware/target/arm/imx31/gigabeat-s/gpio-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/gpio-target.h | |||
@@ -21,11 +21,22 @@ | |||
21 | #ifndef GPIO_TARGET_H | 21 | #ifndef GPIO_TARGET_H |
22 | #define GPIO_TARGET_H | 22 | #define GPIO_TARGET_H |
23 | 23 | ||
24 | #define GPIO_EVENT_MASK (USE_GPIO1_EVENTS) | 24 | /* MC13783 GPIO pin info for this target */ |
25 | |||
26 | #define MC13783_GPIO_NUM GPIO1_NUM | 25 | #define MC13783_GPIO_NUM GPIO1_NUM |
27 | #define MC13783_GPIO_ISR GPIO1_ISR | 26 | #define MC13783_GPIO_ISR GPIO1_ISR |
28 | #define MC13783_GPIO_LINE 31 | 27 | #define MC13783_GPIO_LINE 31 |
29 | #define MC13783_EVENT_ID 0 | 28 | |
29 | /* Declare event indexes in priority order in a packed array */ | ||
30 | enum gpio_event_ids | ||
31 | { | ||
32 | /* GPIO1 event IDs */ | ||
33 | MC13783_EVENT_ID = GPIO1_EVENT_FIRST, | ||
34 | /* GPIO2 event IDs */ | ||
35 | /* none defined */ | ||
36 | /* GPIO3 event IDs */ | ||
37 | /* none defined */ | ||
38 | }; | ||
39 | |||
40 | void mc13783_event(void); | ||
30 | 41 | ||
31 | #endif /* GPIO_TARGET_H */ | 42 | #endif /* GPIO_TARGET_H */ |
diff --git a/firmware/target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c new file mode 100644 index 0000000000..67cfc2d886 --- /dev/null +++ b/firmware/target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c | |||
@@ -0,0 +1,72 @@ | |||
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 MC13783 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 "mc13783.h" | ||
24 | #include "mc13783-target.h" | ||
25 | #include "adc-target.h" | ||
26 | #include "button-target.h" | ||
27 | #include "usb-target.h" | ||
28 | #include "power-imx31.h" | ||
29 | |||
30 | /* Gigabeat S definitions for static MC13783 event registration */ | ||
31 | |||
32 | static const struct mc13783_event mc13783_events[] = | ||
33 | { | ||
34 | [MC13783_ADCDONE_EVENT] = /* ADC conversion complete */ | ||
35 | { | ||
36 | .set = MC13783_EVENT_SET0, | ||
37 | .mask = MC13783_ADCDONEM, | ||
38 | .callback = adc_done, | ||
39 | }, | ||
40 | [MC13783_ONOFD1_EVENT] = /* Power button */ | ||
41 | { | ||
42 | .set = MC13783_EVENT_SET1, | ||
43 | .mask = MC13783_ONOFD1M, | ||
44 | .callback = button_power_event, | ||
45 | }, | ||
46 | #ifdef HAVE_HEADPHONE_DETECTION | ||
47 | [MC13783_ONOFD2_EVENT] = /* Headphone jack */ | ||
48 | { | ||
49 | .set = MC13783_EVENT_SET1, | ||
50 | .mask = MC13783_ONOFD2M, | ||
51 | .callback = headphone_detect_event, | ||
52 | }, | ||
53 | #endif | ||
54 | [MC13783_CHGDET_EVENT] = /* Charger detection */ | ||
55 | { | ||
56 | .set = MC13783_EVENT_SET0, | ||
57 | .mask = MC13783_CHGDETM, | ||
58 | .callback = charger_detect_event, | ||
59 | }, | ||
60 | [MC13783_USB4V4_EVENT] = /* USB insertion */ | ||
61 | { | ||
62 | .set = MC13783_EVENT_SET0, | ||
63 | .mask = MC13783_USB4V4M, | ||
64 | .callback = usb_connect_event, | ||
65 | }, | ||
66 | }; | ||
67 | |||
68 | const struct mc13783_event_list mc13783_event_list = | ||
69 | { | ||
70 | .count = ARRAYLEN(mc13783_events), | ||
71 | .events = mc13783_events | ||
72 | }; | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c b/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c index 4f2bd9d931..097e81d7a3 100644 --- a/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c | |||
@@ -49,121 +49,86 @@ static struct spi_node mc13783_spi = | |||
49 | 0, /* SPI clock - no wait states */ | 49 | 0, /* SPI clock - no wait states */ |
50 | }; | 50 | }; |
51 | 51 | ||
52 | static int mc13783_thread_stack[DEFAULT_STACK_SIZE/sizeof(int)]; | 52 | extern const struct mc13783_event_list mc13783_event_list; |
53 | |||
54 | static int mc13783_thread_stack[3*DEFAULT_STACK_SIZE/sizeof(int)]; | ||
53 | static const char *mc13783_thread_name = "pmic"; | 55 | static const char *mc13783_thread_name = "pmic"; |
54 | static struct wakeup mc13783_wake; | 56 | static struct wakeup mc13783_wake; |
57 | |||
58 | /* Tracking for which interrupts are enabled */ | ||
59 | static uint32_t pmic_int_enabled[2] = | ||
60 | { 0x00000000, 0x00000000 }; | ||
61 | |||
62 | static const unsigned char pmic_intm_regs[2] = | ||
63 | { MC13783_INTERRUPT_MASK0, MC13783_INTERRUPT_MASK1 }; | ||
64 | |||
65 | static const unsigned char pmic_ints_regs[2] = | ||
66 | { MC13783_INTERRUPT_STATUS0, MC13783_INTERRUPT_STATUS1 }; | ||
67 | |||
55 | #ifdef PMIC_DRIVER_CLOSE | 68 | #ifdef PMIC_DRIVER_CLOSE |
56 | static bool pmic_close = false; | 69 | static bool pmic_close = false; |
57 | static struct thread_entry *mc13783_thread_p = NULL; | 70 | static struct thread_entry *mc13783_thread_p = NULL; |
58 | #endif | 71 | #endif |
59 | 72 | ||
60 | /* The next two functions are rather target-specific but they'll just be left | ||
61 | * here for the moment */ | ||
62 | static void mc13783_interrupt_thread(void) | 73 | static void mc13783_interrupt_thread(void) |
63 | { | 74 | { |
64 | const unsigned char status_regs[2] = | ||
65 | { | ||
66 | MC13783_INTERRUPT_STATUS0, | ||
67 | MC13783_INTERRUPT_STATUS1, | ||
68 | }; | ||
69 | uint32_t pending[2]; | 75 | uint32_t pending[2]; |
70 | uint32_t value; | ||
71 | |||
72 | mc13783_read_regset(status_regs, pending, 2); | ||
73 | mc13783_write_regset(status_regs, pending, 2); | ||
74 | |||
75 | gpio_enable_event(MC13783_GPIO_NUM, MC13783_EVENT_ID); | ||
76 | |||
77 | if (pending[1] & MC13783_TODAI) /* only needs to be polled on startup */ | ||
78 | mc13783_alarm_start(); | ||
79 | |||
80 | /* Check initial states for events with a sense bit */ | ||
81 | value = mc13783_read(MC13783_INTERRUPT_SENSE0); | ||
82 | usb_set_status(value & MC13783_USB4V4S); | ||
83 | set_charger_inserted(value & MC13783_CHGDETS); | ||
84 | |||
85 | value = mc13783_read(MC13783_INTERRUPT_SENSE1); | ||
86 | button_power_set_state((value & MC13783_ONOFD1S) == 0); | ||
87 | #ifdef HAVE_HEADPHONE_DETECTION | ||
88 | set_headphones_inserted((value & MC13783_ONOFD2S) == 0); | ||
89 | #endif | ||
90 | 76 | ||
91 | pending[0] = pending[1] = 0xffffff; | 77 | /* Enable mc13783 GPIO event */ |
92 | mc13783_write_regset(status_regs, pending, 2); | 78 | gpio_enable_event(MC13783_EVENT_ID); |
93 | 79 | ||
94 | /* Enable desired PMIC interrupts - some are unmasked in the drivers that | ||
95 | * handle a specific task */ | ||
96 | mc13783_clear(MC13783_INTERRUPT_MASK0, MC13783_CHGDETM); | ||
97 | mc13783_clear(MC13783_INTERRUPT_MASK1, MC13783_ONOFD1M | | ||
98 | MC13783_ONOFD2M); | ||
99 | |||
100 | while (1) | 80 | while (1) |
101 | { | 81 | { |
82 | const struct mc13783_event *event, *event_last; | ||
83 | |||
102 | wakeup_wait(&mc13783_wake, TIMEOUT_BLOCK); | 84 | wakeup_wait(&mc13783_wake, TIMEOUT_BLOCK); |
103 | 85 | ||
104 | #ifdef PMIC_DRIVER_CLOSE | 86 | #ifdef PMIC_DRIVER_CLOSE |
105 | if (pmic_close) | 87 | if (pmic_close) |
106 | { | 88 | break; |
107 | gpio_disable_event(MC13783_GPIO_NUM, MC13783_EVENT_ID); | ||
108 | return; | ||
109 | } | ||
110 | #endif | 89 | #endif |
111 | 90 | ||
112 | mc13783_read_regset(status_regs, pending, 2); | 91 | mc13783_read_regset(pmic_ints_regs, pending, 2); |
113 | mc13783_write_regset(status_regs, pending, 2); | ||
114 | |||
115 | if (pending[0]) | ||
116 | { | ||
117 | /* Handle ...PENDING0 */ | ||
118 | |||
119 | /* Handle interrupts without a sense bit */ | ||
120 | if (pending[0] & MC13783_ADCDONEI) | ||
121 | adc_done(); | ||
122 | 92 | ||
123 | /* Handle interrupts that have a sense bit that needs to | 93 | /* Only clear interrupts being dispatched */ |
124 | * be checked */ | 94 | pending[0] &= pmic_int_enabled[0]; |
125 | if (pending[0] & (MC13783_CHGDETI | MC13783_USB4V4I)) | 95 | pending[1] &= pmic_int_enabled[1]; |
126 | { | ||
127 | value = mc13783_read(MC13783_INTERRUPT_SENSE0); | ||
128 | 96 | ||
129 | if (pending[0] & MC13783_CHGDETI) | 97 | mc13783_write_regset(pmic_ints_regs, pending, 2); |
130 | set_charger_inserted(value & MC13783_CHGDETS); | ||
131 | 98 | ||
132 | if (pending[0] & MC13783_USB4V4I) | 99 | event = mc13783_event_list.events; |
133 | usb_set_status(value & MC13783_USB4V4S); | 100 | event_last = event + mc13783_event_list.count; |
134 | } | ||
135 | } | ||
136 | 101 | ||
137 | if (pending[1]) | 102 | /* .count is surely expected to be > 0 */ |
103 | do | ||
138 | { | 104 | { |
139 | /* Handle ...PENDING1 */ | 105 | enum mc13783_event_sets set = event->set; |
140 | 106 | uint32_t pnd = pending[set]; | |
141 | /* Handle interrupts without a sense bit */ | 107 | uint32_t mask = event->mask; |
142 | /* ... */ | ||
143 | 108 | ||
144 | /* Handle interrupts that have a sense bit that needs to | 109 | if (pnd & mask) |
145 | * be checked */ | ||
146 | if (pending[1] & (MC13783_ONOFD1I | MC13783_ONOFD2I)) | ||
147 | { | 110 | { |
148 | value = mc13783_read(MC13783_INTERRUPT_SENSE1); | 111 | event->callback(); |
149 | 112 | pnd &= ~mask; | |
150 | if (pending[1] & MC13783_ONOFD1I) | 113 | pending[set] = pnd; |
151 | button_power_set_state((value & MC13783_ONOFD1S) == 0); | ||
152 | #ifdef HAVE_HEADPHONE_DETECTION | ||
153 | if (pending[1] & MC13783_ONOFD2I) | ||
154 | set_headphones_inserted((value & MC13783_ONOFD2S) == 0); | ||
155 | #endif | ||
156 | } | 114 | } |
115 | |||
116 | if ((pending[0] | pending[1]) == 0) | ||
117 | break; /* Teminate early if nothing more to service */ | ||
157 | } | 118 | } |
119 | while (++event < event_last); | ||
158 | } | 120 | } |
121 | |||
122 | #ifdef PMIC_DRIVER_CLOSE | ||
123 | gpio_disable_event(MC13783_EVENT_ID); | ||
124 | #endif | ||
159 | } | 125 | } |
160 | 126 | ||
161 | /* GPIO interrupt handler for mc13783 */ | 127 | /* GPIO interrupt handler for mc13783 */ |
162 | int mc13783_event(void) | 128 | void mc13783_event(void) |
163 | { | 129 | { |
164 | MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE); | 130 | MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE); |
165 | wakeup_signal(&mc13783_wake); | 131 | wakeup_signal(&mc13783_wake); |
166 | return 1; /* Yes, it's handled */ | ||
167 | } | 132 | } |
168 | 133 | ||
169 | void mc13783_init(void) | 134 | void mc13783_init(void) |
@@ -174,8 +139,8 @@ void mc13783_init(void) | |||
174 | /* Enable the PMIC SPI module */ | 139 | /* Enable the PMIC SPI module */ |
175 | spi_enable_module(&mc13783_spi); | 140 | spi_enable_module(&mc13783_spi); |
176 | 141 | ||
177 | /* Mask any PMIC interrupts for now - poll initial status in thread | 142 | /* Mask any PMIC interrupts for now - modules will enable them as |
178 | * and enable them there */ | 143 | * required */ |
179 | mc13783_write(MC13783_INTERRUPT_MASK0, 0xffffff); | 144 | mc13783_write(MC13783_INTERRUPT_MASK0, 0xffffff); |
180 | mc13783_write(MC13783_INTERRUPT_MASK1, 0xffffff); | 145 | mc13783_write(MC13783_INTERRUPT_MASK1, 0xffffff); |
181 | 146 | ||
@@ -203,7 +168,39 @@ void mc13783_close(void) | |||
203 | wakeup_signal(&mc13783_wake); | 168 | wakeup_signal(&mc13783_wake); |
204 | thread_wait(thread); | 169 | thread_wait(thread); |
205 | } | 170 | } |
206 | #endif | 171 | #endif /* PMIC_DRIVER_CLOSE */ |
172 | |||
173 | bool mc13783_enable_event(enum mc13783_event_ids id) | ||
174 | { | ||
175 | const struct mc13783_event * const event = | ||
176 | &mc13783_event_list.events[id]; | ||
177 | int set = event->set; | ||
178 | uint32_t mask = event->mask; | ||
179 | |||
180 | spi_lock(&mc13783_spi); | ||
181 | |||
182 | pmic_int_enabled[set] |= mask; | ||
183 | mc13783_clear(pmic_intm_regs[set], mask); | ||
184 | |||
185 | spi_unlock(&mc13783_spi); | ||
186 | |||
187 | return true; | ||
188 | } | ||
189 | |||
190 | void mc13783_disable_event(enum mc13783_event_ids id) | ||
191 | { | ||
192 | const struct mc13783_event * const event = | ||
193 | &mc13783_event_list.events[id]; | ||
194 | int set = event->set; | ||
195 | uint32_t mask = event->mask; | ||
196 | |||
197 | spi_lock(&mc13783_spi); | ||
198 | |||
199 | pmic_int_enabled[set] &= ~mask; | ||
200 | mc13783_set(pmic_intm_regs[set], mask); | ||
201 | |||
202 | spi_unlock(&mc13783_spi); | ||
203 | } | ||
207 | 204 | ||
208 | uint32_t mc13783_set(unsigned address, uint32_t bits) | 205 | uint32_t mc13783_set(unsigned address, uint32_t bits) |
209 | { | 206 | { |
diff --git a/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h b/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h new file mode 100644 index 0000000000..a74a229f04 --- /dev/null +++ b/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h | |||
@@ -0,0 +1,36 @@ | |||
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 mc13783 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 | #ifndef MC13783_TARGET_H | ||
22 | #define MC13783_TARGET_H | ||
23 | |||
24 | /* Declare event indexes in priority order in a packed array */ | ||
25 | enum mc13783_event_ids | ||
26 | { | ||
27 | MC13783_ADCDONE_EVENT = 0, /* ADC conversion complete */ | ||
28 | MC13783_ONOFD1_EVENT, /* Power button */ | ||
29 | #ifdef HAVE_HEADPHONE_DETECTION | ||
30 | MC13783_ONOFD2_EVENT, /* Headphone jack */ | ||
31 | #endif | ||
32 | MC13783_CHGDET_EVENT, /* Charger detection */ | ||
33 | MC13783_USB4V4_EVENT, /* USB insertion */ | ||
34 | }; | ||
35 | |||
36 | #endif /* MC13783_TARGET_H */ | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/power-imx31.c b/firmware/target/arm/imx31/gigabeat-s/power-imx31.c index 53cdb7c315..8db59bdf0e 100644 --- a/firmware/target/arm/imx31/gigabeat-s/power-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/power-imx31.c | |||
@@ -28,14 +28,11 @@ | |||
28 | 28 | ||
29 | static bool charger_detect = false; | 29 | static bool charger_detect = false; |
30 | 30 | ||
31 | void power_init(void) | ||
32 | { | ||
33 | } | ||
34 | |||
35 | /* This is called from the mc13783 interrupt thread */ | 31 | /* This is called from the mc13783 interrupt thread */ |
36 | void set_charger_inserted(bool inserted) | 32 | void charger_detect_event(void) |
37 | { | 33 | { |
38 | charger_detect = inserted; | 34 | charger_detect = |
35 | mc13783_read(MC13783_INTERRUPT_SENSE0) & MC13783_CHGDETS; | ||
39 | } | 36 | } |
40 | 37 | ||
41 | bool charger_inserted(void) | 38 | bool charger_inserted(void) |
@@ -81,6 +78,15 @@ void power_off(void) | |||
81 | while (1); | 78 | while (1); |
82 | } | 79 | } |
83 | 80 | ||
81 | void power_init(void) | ||
82 | { | ||
83 | /* Poll initial state */ | ||
84 | charger_detect_event(); | ||
85 | |||
86 | /* Enable detect event */ | ||
87 | mc13783_enable_event(MC13783_CHGDET_EVENT); | ||
88 | } | ||
89 | |||
84 | #else /* SIMULATOR */ | 90 | #else /* SIMULATOR */ |
85 | 91 | ||
86 | bool charger_inserted(void) | 92 | bool charger_inserted(void) |
diff --git a/firmware/target/arm/imx31/gigabeat-s/power-imx31.h b/firmware/target/arm/imx31/gigabeat-s/power-imx31.h index bb0a7614d8..b949d41d35 100644 --- a/firmware/target/arm/imx31/gigabeat-s/power-imx31.h +++ b/firmware/target/arm/imx31/gigabeat-s/power-imx31.h | |||
@@ -19,6 +19,6 @@ | |||
19 | #ifndef POWER_IMX31_H | 19 | #ifndef POWER_IMX31_H |
20 | #define POWER_IMX31_H | 20 | #define POWER_IMX31_H |
21 | 21 | ||
22 | void set_charger_inserted(bool inserted); | 22 | void charger_detect_event(void); |
23 | 23 | ||
24 | #endif /* POWER_IMX31_H */ | 24 | #endif /* POWER_IMX31_H */ |
diff --git a/firmware/target/arm/imx31/gigabeat-s/usb-imx31.c b/firmware/target/arm/imx31/gigabeat-s/usb-imx31.c index f12fd8f0b1..ad6c77138c 100644 --- a/firmware/target/arm/imx31/gigabeat-s/usb-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/usb-imx31.c | |||
@@ -48,9 +48,10 @@ static void enable_transceiver(bool enable) | |||
48 | } | 48 | } |
49 | } | 49 | } |
50 | 50 | ||
51 | void usb_set_status(bool plugged) | 51 | void usb_connect_event(void) |
52 | { | 52 | { |
53 | usb_status = plugged ? USB_INSERTED : USB_EXTRACTED; | 53 | uint32_t status = mc13783_read(MC13783_INTERRUPT_SENSE0); |
54 | usb_status = (status & MC13783_USB4V4S) ? USB_INSERTED : USB_EXTRACTED; | ||
54 | } | 55 | } |
55 | 56 | ||
56 | int usb_detect(void) | 57 | int usb_detect(void) |
@@ -73,7 +74,11 @@ void usb_init_device(void) | |||
73 | /* Module will be turned off later after firmware init */ | 74 | /* Module will be turned off later after firmware init */ |
74 | usb_drv_startup(); | 75 | usb_drv_startup(); |
75 | 76 | ||
76 | mc13783_clear(MC13783_INTERRUPT_MASK0, MC13783_USB4V4M); | 77 | /* Initially poll */ |
78 | usb_connect_event(); | ||
79 | |||
80 | /* Enable PMIC event */ | ||
81 | mc13783_enable_event(MC13783_USB4V4_EVENT); | ||
77 | } | 82 | } |
78 | 83 | ||
79 | void usb_enable(bool on) | 84 | void usb_enable(bool on) |
diff --git a/firmware/target/arm/imx31/gigabeat-s/usb-target.h b/firmware/target/arm/imx31/gigabeat-s/usb-target.h index c6e2850b9d..0af740ac7c 100644 --- a/firmware/target/arm/imx31/gigabeat-s/usb-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/usb-target.h | |||
@@ -23,7 +23,7 @@ | |||
23 | #define USB_DRIVER_CLOSE | 23 | #define USB_DRIVER_CLOSE |
24 | #endif | 24 | #endif |
25 | 25 | ||
26 | void usb_set_status(bool plugged); | 26 | void usb_connect_event(void); |
27 | bool usb_init_device(void); | 27 | bool usb_init_device(void); |
28 | int usb_detect(void); | 28 | int usb_detect(void); |
29 | /* Read the immediate state of the cable from the PMIC */ | 29 | /* Read the immediate state of the cable from the PMIC */ |