diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2017-01-28 14:43:35 -0500 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2017-01-29 19:07:55 -0500 |
commit | 2220a4b695f2f5ac9fe212de4bcfa5365318136f (patch) | |
tree | ef0b31d798b12cbc5cd61e3f020f1856c1759db4 /firmware/target/arm/imx31 | |
parent | d4303ac900bae6b0fd2320db33bdb4f10861a430 (diff) | |
download | rockbox-2220a4b695f2f5ac9fe212de4bcfa5365318136f.tar.gz rockbox-2220a4b695f2f5ac9fe212de4bcfa5365318136f.zip |
Improve imx31 interrupt code for PMIC and GPIO
Fix stuff that was bugging me about the way I did it at first.
While messing around I found RDS code wasn't masking its GPIO
ISR as it should, which might lead to two different interrupts
messing with the static data.
Change-Id: I54626809ea3039a842af0cc9e3e42853326c4193
Diffstat (limited to 'firmware/target/arm/imx31')
16 files changed, 489 insertions, 444 deletions
diff --git a/firmware/target/arm/imx31/gigabeat-s/adc-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/adc-gigabeat-s.c index b46fc2f63f..2a89a82e46 100644 --- a/firmware/target/arm/imx31/gigabeat-s/adc-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/adc-gigabeat-s.c | |||
@@ -111,7 +111,7 @@ bool adc_enable_channel(int channel, bool enable) | |||
111 | } | 111 | } |
112 | 112 | ||
113 | /* ADC conversion complete event - called from PMIC ISR */ | 113 | /* ADC conversion complete event - called from PMIC ISR */ |
114 | void adc_done(void) | 114 | void MC13783_EVENT_CB_ADCDONE(void) |
115 | { | 115 | { |
116 | semaphore_release(&adc_done_signal); | 116 | semaphore_release(&adc_done_signal); |
117 | } | 117 | } |
@@ -132,5 +132,5 @@ void adc_init(void) | |||
132 | 132 | ||
133 | /* Enable ADCDONE event */ | 133 | /* Enable ADCDONE event */ |
134 | mc13783_write(MC13783_INTERRUPT_STATUS0, MC13783_ADCDONEI); | 134 | mc13783_write(MC13783_INTERRUPT_STATUS0, MC13783_ADCDONEI); |
135 | mc13783_enable_event(MC13783_ADCDONE_EVENT, true); | 135 | mc13783_enable_event(MC13783_INT_ID_ADCDONE, true); |
136 | } | 136 | } |
diff --git a/firmware/target/arm/imx31/gigabeat-s/adc-target.h b/firmware/target/arm/imx31/gigabeat-s/adc-target.h index 00027e05df..dbca920b26 100644 --- a/firmware/target/arm/imx31/gigabeat-s/adc-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/adc-target.h | |||
@@ -46,7 +46,6 @@ | |||
46 | #define ADC_UNREG_POWER ADC_BATTERY /* For compatibility */ | 46 | #define ADC_UNREG_POWER ADC_BATTERY /* For compatibility */ |
47 | #define ADC_READ_ERROR 0xFFFF | 47 | #define ADC_READ_ERROR 0xFFFF |
48 | 48 | ||
49 | void adc_done(void); | ||
50 | /* Enable conversion of specified channel (if switchoff is possible) */ | 49 | /* Enable conversion of specified channel (if switchoff is possible) */ |
51 | bool adc_enable_channel(int channel, bool enable); | 50 | bool adc_enable_channel(int channel, bool enable); |
52 | 51 | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/button-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/button-gigabeat-s.c index 3972e5722f..cdd6da041b 100644 --- a/firmware/target/arm/imx31/gigabeat-s/button-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/button-gigabeat-s.c | |||
@@ -157,9 +157,9 @@ static void power_button_update(bool pressed) | |||
157 | } | 157 | } |
158 | 158 | ||
159 | /* Power button event - called from PMIC ISR */ | 159 | /* Power button event - called from PMIC ISR */ |
160 | void button_power_event(void) | 160 | void MC13783_EVENT_CB_ONOFD1(void) |
161 | { | 161 | { |
162 | power_button_update(!mc13783_event_sense(MC13783_ONOFD1_EVENT)); | 162 | power_button_update(!mc13783_event_sense()); |
163 | } | 163 | } |
164 | 164 | ||
165 | void button_init_device(void) | 165 | void button_init_device(void) |
@@ -197,7 +197,7 @@ void button_init_device(void) | |||
197 | 197 | ||
198 | power_button_update(!(mc13783_read(MC13783_INTERRUPT_SENSE1) | 198 | power_button_update(!(mc13783_read(MC13783_INTERRUPT_SENSE1) |
199 | & MC13783_ONOFD1S)); | 199 | & MC13783_ONOFD1S)); |
200 | mc13783_enable_event(MC13783_ONOFD1_EVENT, true); | 200 | mc13783_enable_event(MC13783_INT_ID_ONOFD1, true); |
201 | 201 | ||
202 | #ifdef HAVE_HEADPHONE_DETECTION | 202 | #ifdef HAVE_HEADPHONE_DETECTION |
203 | headphone_init(); | 203 | headphone_init(); |
@@ -213,7 +213,7 @@ void button_close_device(void) | |||
213 | /* Assumes HP detection is not available */ | 213 | /* Assumes HP detection is not available */ |
214 | initialized = false; | 214 | initialized = false; |
215 | 215 | ||
216 | mc13783_enable_event(MC13783_ONOFD1_EVENT, false); | 216 | mc13783_enable_event(MC13783_INT_ID_ONOFD1, false); |
217 | ext_btn = BUTTON_NONE; | 217 | ext_btn = BUTTON_NONE; |
218 | } | 218 | } |
219 | #endif /* BUTTON_DRIVER_CLOSE */ | 219 | #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 ce624ed6cc..fba02d5dd2 100644 --- a/firmware/target/arm/imx31/gigabeat-s/button-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/button-target.h | |||
@@ -30,8 +30,6 @@ | |||
30 | #endif | 30 | #endif |
31 | 31 | ||
32 | void button_close_device(void); | 32 | void button_close_device(void); |
33 | void button_power_event(void); | ||
34 | void headphone_detect_event(void); | ||
35 | void headphone_init(void); | 33 | void headphone_init(void); |
36 | void button_headphone_set(int button); | 34 | void button_headphone_set(int button); |
37 | 35 | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c index 108a6d0944..ee91b99c0f 100644 --- a/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c | |||
@@ -26,7 +26,7 @@ | |||
26 | #include "thread.h" | 26 | #include "thread.h" |
27 | #include "mc13783.h" | 27 | #include "mc13783.h" |
28 | #include "iomuxc-imx31.h" | 28 | #include "iomuxc-imx31.h" |
29 | #include "gpio-imx31.h" | 29 | #include "gpio-target.h" |
30 | #include "i2c-imx31.h" | 30 | #include "i2c-imx31.h" |
31 | #include "fmradio_i2c.h" | 31 | #include "fmradio_i2c.h" |
32 | #include "rds.h" | 32 | #include "rds.h" |
@@ -139,20 +139,25 @@ static struct si4700_i2c_transfer_desc | |||
139 | .xfer = { .node = &si4700_i2c_node } | 139 | .xfer = { .node = &si4700_i2c_node } |
140 | }; | 140 | }; |
141 | 141 | ||
142 | static bool int_restore; | ||
143 | |||
142 | static void si4700_rds_read_raw_callback(struct i2c_transfer_desc *xfer) | 144 | static void si4700_rds_read_raw_callback(struct i2c_transfer_desc *xfer) |
143 | { | 145 | { |
144 | struct si4700_i2c_transfer_desc *xf = | 146 | struct si4700_i2c_transfer_desc *xf = |
145 | (struct si4700_i2c_transfer_desc *)xfer; | 147 | (struct si4700_i2c_transfer_desc *)xfer; |
146 | 148 | ||
147 | if (xfer->rxcount != 0) | 149 | if (xfer->rxcount == 0) |
148 | return; /* Read didn't finish */ | 150 | { |
149 | 151 | uint16_t rds_data[4]; | |
150 | uint16_t rds_data[4]; | 152 | si4700_rds_read_raw_async_complete(xf->regbuf, rds_data); |
151 | 153 | ||
152 | si4700_rds_read_raw_async_complete(xf->regbuf, rds_data); | 154 | if (rds_process(rds_data)) |
155 | si4700_rds_set_event(); | ||
156 | } | ||
157 | /* else read didn't finish */ | ||
153 | 158 | ||
154 | if (rds_process(rds_data)) | 159 | if (int_restore) |
155 | si4700_rds_set_event(); | 160 | gpio_int_enable(SI4700_EVENT_ID); |
156 | } | 161 | } |
157 | 162 | ||
158 | /* Callback from si4700_rds_read_raw to execute the read */ | 163 | /* Callback from si4700_rds_read_raw to execute the read */ |
@@ -169,10 +174,13 @@ void si4700_read_raw_async(int count) | |||
169 | } | 174 | } |
170 | 175 | ||
171 | /* RDS GPIO interrupt handler - start RDS data read */ | 176 | /* RDS GPIO interrupt handler - start RDS data read */ |
172 | void si4700_stc_rds_event(void) | 177 | void INT_SI4700_RDS(void) |
173 | { | 178 | { |
174 | /* read and clear the interrupt */ | 179 | /* mask and clear the interrupt */ |
175 | SI4700_GPIO_STC_RDS_ISR = (1ul << SI4700_GPIO_STC_RDS_LINE); | 180 | gpio_int_disable(SI4700_EVENT_ID); |
181 | gpio_int_clear(SI4700_EVENT_ID); | ||
182 | |||
183 | /* read the RDS data */ | ||
176 | si4700_rds_read_raw_async(); | 184 | si4700_rds_read_raw_async(); |
177 | } | 185 | } |
178 | 186 | ||
@@ -180,13 +188,10 @@ void si4700_stc_rds_event(void) | |||
180 | powering down */ | 188 | powering down */ |
181 | void si4700_rds_powerup(bool on) | 189 | void si4700_rds_powerup(bool on) |
182 | { | 190 | { |
183 | gpio_disable_event(SI4700_STC_RDS_EVENT_ID); | 191 | int_restore = on; |
184 | 192 | gpio_int_disable(SI4700_EVENT_ID); | |
185 | if (on) | 193 | gpio_int_clear(SI4700_EVENT_ID); |
186 | { | 194 | gpio_enable_event(SI4700_EVENT_ID, on); |
187 | SI4700_GPIO_STC_RDS_ISR = (1ul << SI4700_GPIO_STC_RDS_LINE); | ||
188 | gpio_enable_event(SI4700_STC_RDS_EVENT_ID); | ||
189 | } | ||
190 | } | 195 | } |
191 | 196 | ||
192 | /* One-time RDS init at startup */ | 197 | /* One-time RDS init at startup */ |
diff --git a/firmware/target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c deleted file mode 100644 index 51446934aa..0000000000 --- a/firmware/target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c +++ /dev/null | |||
@@ -1,52 +0,0 @@ | |||
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 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #include "config.h" | ||
24 | #include "system.h" | ||
25 | #include "avic-imx31.h" | ||
26 | #include "gpio-imx31.h" | ||
27 | |||
28 | /* Gigabeat S definitions for static GPIO event registration */ | ||
29 | |||
30 | /* Describes single events for each GPIO1 pin */ | ||
31 | const struct gpio_event gpio1_events[] = | ||
32 | { | ||
33 | /* mc13783 keeps the PRIINT high (no low pulse) if other unmasked | ||
34 | * interrupts become active when clearing them or if a source being | ||
35 | * cleared becomes active at that time. Edge-detection will not get | ||
36 | * a rising edge in that case so use high-level sense. */ | ||
37 | [MC13783_EVENT_ID-GPIO1_EVENT_FIRST] = | ||
38 | { | ||
39 | .mask = 1 << MC13783_GPIO_LINE, | ||
40 | .sense = GPIO_SENSE_HIGH_LEVEL, | ||
41 | .callback = mc13783_event, | ||
42 | }, | ||
43 | #ifndef BOOTLOADER | ||
44 | /* Generates a 5ms low pulse on the line - detect the falling edge */ | ||
45 | [SI4700_STC_RDS_EVENT_ID] = | ||
46 | { | ||
47 | .mask = 1 << SI4700_GPIO_STC_RDS_LINE, | ||
48 | .sense = GPIO_SENSE_FALLING, | ||
49 | .callback = si4700_stc_rds_event, | ||
50 | }, | ||
51 | #endif | ||
52 | }; | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/gpio-target.h b/firmware/target/arm/imx31/gigabeat-s/gpio-target.h index 4903d0f631..543b25f244 100644 --- a/firmware/target/arm/imx31/gigabeat-s/gpio-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/gpio-target.h | |||
@@ -23,34 +23,33 @@ | |||
23 | #ifndef GPIO_TARGET_H | 23 | #ifndef GPIO_TARGET_H |
24 | #define GPIO_TARGET_H | 24 | #define GPIO_TARGET_H |
25 | 25 | ||
26 | /* MC13783 GPIO pin info for this target */ | 26 | /* Gigabeat S definitions for static GPIO event registration */ |
27 | #define MC13783_GPIO_IMR GPIO1_IMR | 27 | #include "gpio-imx31.h" |
28 | #define MC13783_GPIO_NUM GPIO1_NUM | 28 | |
29 | #define MC13783_GPIO_ISR GPIO1_ISR | 29 | #ifdef DEFINE_GPIO_VECTOR_TABLE |
30 | #define MC13783_GPIO_LINE 31 | 30 | |
31 | 31 | GPIO_VECTOR_TBL_START() | |
32 | /* SI4700 GPIO STC/RDS pin info for this target */ | 32 | /* mc13783 keeps the PRIINT high (no low pulse) if other unmasked |
33 | #define SI4700_GPIO_STC_RDS_IMR GPIO1_IMR | 33 | * interrupts become active when clearing them or if a source being |
34 | #define SI4700_GPIO_STC_RDS_NUM GPIO1_NUM | 34 | * cleared becomes active at that time. Edge-detection will not get |
35 | #define SI4700_GPIO_STC_RDS_ISR GPIO1_ISR | 35 | * a rising edge in that case so use high-level sense. */ |
36 | #define SI4700_GPIO_STC_RDS_LINE 27 | 36 | GPIO_EVENT_VECTOR(GPIO1_31, GPIO_SENSE_HIGH_LEVEL) |
37 | #if CONFIG_TUNER | ||
38 | /* Generates a 5ms low pulse on the line - detect the falling edge */ | ||
39 | GPIO_EVENT_VECTOR(GPIO1_27, GPIO_SENSE_FALLING) | ||
40 | #endif /* CONFIG_TUNER */ | ||
41 | GPIO_VECTOR_TBL_END() | ||
37 | 42 | ||
38 | #define GPIO1_INT_PRIO INT_PRIO_DEFAULT | 43 | #define GPIO1_INT_PRIO INT_PRIO_DEFAULT |
39 | 44 | ||
40 | /* Declare event indexes in priority order in a packed array */ | 45 | #endif /* DEFINE_GPIO_VECTOR_TABLE */ |
41 | enum gpio_event_ids | 46 | |
42 | { | 47 | #define INT_MC13783 GPIO1_31_EVENT_CB |
43 | /* GPIO1 event IDs */ | 48 | #define MC13783_EVENT_ID GPIO1_31_ID |
44 | MC13783_EVENT_ID = GPIO1_EVENT_FIRST, | 49 | |
45 | SI4700_STC_RDS_EVENT_ID, | 50 | #if CONFIG_TUNER |
46 | GPIO1_NUM_EVENTS = 2, | 51 | #define INT_SI4700_RDS GPIO1_27_EVENT_CB |
47 | /* GPIO2 event IDs */ | 52 | #define SI4700_EVENT_ID GPIO1_27_ID |
48 | /* none defined */ | 53 | #endif /* CONFIG_TUNER */ |
49 | /* GPIO3 event IDs */ | ||
50 | /* none defined */ | ||
51 | }; | ||
52 | |||
53 | void mc13783_event(void); | ||
54 | void si4700_stc_rds_event(void); | ||
55 | 54 | ||
56 | #endif /* GPIO_TARGET_H */ | 55 | #endif /* GPIO_TARGET_H */ |
diff --git a/firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c index 6fdde32185..cf0a378fc7 100644 --- a/firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include "kernel.h" | 25 | #include "kernel.h" |
26 | #include "thread.h" | 26 | #include "thread.h" |
27 | #include "mc13783.h" | 27 | #include "mc13783.h" |
28 | #include "mc13783-target.h" | ||
29 | #include "adc.h" | 28 | #include "adc.h" |
30 | #include "button.h" | 29 | #include "button.h" |
31 | 30 | ||
@@ -146,7 +145,7 @@ static void NORETURN_ATTR headphone_thread(void) | |||
146 | } | 145 | } |
147 | 146 | ||
148 | /* HP plugged/unplugged event - called from PMIC ISR */ | 147 | /* HP plugged/unplugged event - called from PMIC ISR */ |
149 | void headphone_detect_event(void) | 148 | void MC13783_EVENT_CB_ONOFD2(void) |
150 | { | 149 | { |
151 | /* Trigger the thread immediately. */ | 150 | /* Trigger the thread immediately. */ |
152 | semaphore_release(&headphone_wakeup); | 151 | semaphore_release(&headphone_wakeup); |
@@ -170,5 +169,5 @@ void INIT_ATTR headphone_init(void) | |||
170 | IF_COP(, CPU)); | 169 | IF_COP(, CPU)); |
171 | 170 | ||
172 | /* Enable PMIC event */ | 171 | /* Enable PMIC event */ |
173 | mc13783_enable_event(MC13783_ONOFD2_EVENT, true); | 172 | mc13783_enable_event(MC13783_INT_ID_ONOFD2, true); |
174 | } | 173 | } |
diff --git a/firmware/target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c deleted file mode 100644 index 76001dddd6..0000000000 --- a/firmware/target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c +++ /dev/null | |||
@@ -1,86 +0,0 @@ | |||
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 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #include "config.h" | ||
24 | #include "system.h" | ||
25 | #include "spi-imx31.h" | ||
26 | #include "mc13783.h" | ||
27 | #include "mc13783-target.h" | ||
28 | #include "adc-target.h" | ||
29 | #include "button-target.h" | ||
30 | #include "power-gigabeat-s.h" | ||
31 | #include "powermgmt-target.h" | ||
32 | |||
33 | /* Gigabeat S mc13783 serial interface node. */ | ||
34 | |||
35 | struct spi_node mc13783_spi = | ||
36 | { | ||
37 | /* Based upon original firmware settings */ | ||
38 | CSPI2_NUM, /* CSPI module 2 */ | ||
39 | CSPI_CONREG_CHIP_SELECT_SS0 | /* Chip select 0 */ | ||
40 | CSPI_CONREG_DRCTL_DONT_CARE | /* Don't care about CSPI_RDY */ | ||
41 | CSPI_CONREG_DATA_RATE_DIV_32 | /* Clock = IPG_CLK/32 = 2,062,500Hz. */ | ||
42 | CSPI_BITCOUNT(32-1) | /* All 32 bits are to be transferred */ | ||
43 | CSPI_CONREG_SSPOL | /* SS active high */ | ||
44 | CSPI_CONREG_SSCTL | /* Negate SS between SPI bursts */ | ||
45 | CSPI_CONREG_MODE, /* Master mode */ | ||
46 | 0, /* SPI clock - no wait states */ | ||
47 | }; | ||
48 | |||
49 | |||
50 | /* Gigabeat S definitions for static MC13783 event registration */ | ||
51 | |||
52 | const struct mc13783_event mc13783_events[MC13783_NUM_EVENTS] = | ||
53 | { | ||
54 | [MC13783_ADCDONE_EVENT] = /* ADC conversion complete */ | ||
55 | { | ||
56 | .int_id = MC13783_INT_ID_ADCDONE, | ||
57 | .sense = 0, | ||
58 | .callback = adc_done, | ||
59 | }, | ||
60 | [MC13783_ONOFD1_EVENT] = /* Power button */ | ||
61 | { | ||
62 | .int_id = MC13783_INT_ID_ONOFD1, | ||
63 | .sense = MC13783_ONOFD1S, | ||
64 | .callback = button_power_event, | ||
65 | }, | ||
66 | [MC13783_SE1_EVENT] = /* Main charger detection */ | ||
67 | { | ||
68 | .int_id = MC13783_INT_ID_SE1, | ||
69 | .sense = MC13783_SE1S, | ||
70 | .callback = charger_main_detect_event, | ||
71 | }, | ||
72 | [MC13783_USB_EVENT] = /* USB insertion/USB charger detection */ | ||
73 | { | ||
74 | .int_id = MC13783_INT_ID_USB, | ||
75 | .sense = MC13783_USB4V4S, | ||
76 | .callback = usb_connect_event, | ||
77 | }, | ||
78 | #ifdef HAVE_HEADPHONE_DETECTION | ||
79 | [MC13783_ONOFD2_EVENT] = /* Headphone jack */ | ||
80 | { | ||
81 | .int_id = MC13783_INT_ID_ONOFD2, | ||
82 | .sense = 0, | ||
83 | .callback = headphone_detect_event, | ||
84 | }, | ||
85 | #endif | ||
86 | }; | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h b/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h index 48d634035a..179c65cad6 100644 --- a/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h | |||
@@ -23,17 +23,41 @@ | |||
23 | #ifndef MC13783_TARGET_H | 23 | #ifndef MC13783_TARGET_H |
24 | #define MC13783_TARGET_H | 24 | #define MC13783_TARGET_H |
25 | 25 | ||
26 | /* Declare event indexes in priority order in a packed array */ | 26 | #include "mc13783.h" |
27 | enum mc13783_event_ids | 27 | |
28 | #ifdef DEFINE_MC13783_VECTOR_TABLE | ||
29 | |||
30 | /* Gigabeat S mc13783 serial interface node. */ | ||
31 | static struct spi_node mc13783_spi = | ||
28 | { | 32 | { |
29 | MC13783_ADCDONE_EVENT = 0, /* ADC conversion complete */ | 33 | /* Based upon original firmware settings */ |
30 | MC13783_ONOFD1_EVENT, /* Power button */ | 34 | CSPI2_NUM, /* CSPI module 2 */ |
31 | #ifdef HAVE_HEADPHONE_DETECTION | 35 | CSPI_CONREG_CHIP_SELECT_SS0 | /* Chip select 0 */ |
32 | MC13783_ONOFD2_EVENT, /* Headphone jack */ | 36 | CSPI_CONREG_DRCTL_DONT_CARE | /* Don't care about CSPI_RDY */ |
33 | #endif | 37 | CSPI_CONREG_DATA_RATE_DIV_32 | /* Clock = IPG_CLK/32 = 2,062,500Hz. */ |
34 | MC13783_SE1_EVENT, /* Main charger detection */ | 38 | CSPI_BITCOUNT(32-1) | /* All 32 bits are to be transferred */ |
35 | MC13783_USB_EVENT, /* USB insertion */ | 39 | CSPI_CONREG_SSPOL | /* SS active high */ |
36 | MC13783_NUM_EVENTS, | 40 | CSPI_CONREG_SSCTL | /* Negate SS between SPI bursts */ |
41 | CSPI_CONREG_MODE, /* Master mode */ | ||
42 | 0, /* SPI clock - no wait states */ | ||
37 | }; | 43 | }; |
38 | 44 | ||
45 | /* Gigabeat S definitions for static MC13783 event registration */ | ||
46 | MC13783_EVENT_VECTOR_TBL_START() | ||
47 | /* ADC conversion complete */ | ||
48 | MC13783_EVENT_VECTOR(ADCDONE, 0) | ||
49 | /* Power button */ | ||
50 | MC13783_EVENT_VECTOR(ONOFD1, MC13783_ONOFD1S) | ||
51 | /* Main charger detection */ | ||
52 | MC13783_EVENT_VECTOR(SE1, MC13783_SE1S) | ||
53 | /* USB insertion/USB charger detection */ | ||
54 | MC13783_EVENT_VECTOR(USB, MC13783_USB4V4S) | ||
55 | #ifdef HAVE_HEADPHONE_DETECTION | ||
56 | /* Headphone jack */ | ||
57 | MC13783_EVENT_VECTOR(ONOFD2, 0) | ||
58 | #endif /* HAVE_HEADPHONE_DETECTION */ | ||
59 | MC13783_EVENT_VECTOR_TBL_END() | ||
60 | |||
61 | #endif /* DEFINE_MC13783_VECTOR_TABLE */ | ||
62 | |||
39 | #endif /* MC13783_TARGET_H */ | 63 | #endif /* MC13783_TARGET_H */ |
diff --git a/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c index 5d89802bc9..81f150acd7 100644 --- a/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c | |||
@@ -66,9 +66,9 @@ static void update_main_charger(bool present) | |||
66 | } | 66 | } |
67 | 67 | ||
68 | /* Detect changes in presence of the AC adaptor. Called from PMIC ISR. */ | 68 | /* Detect changes in presence of the AC adaptor. Called from PMIC ISR. */ |
69 | void charger_main_detect_event(void) | 69 | void MC13783_EVENT_CB_SE1(void) |
70 | { | 70 | { |
71 | update_main_charger(mc13783_event_sense(MC13783_SE1_EVENT)); | 71 | update_main_charger(mc13783_event_sense()); |
72 | } | 72 | } |
73 | 73 | ||
74 | /* Detect changes in USB bus power. Called from usb connect event ISR. */ | 74 | /* Detect changes in USB bus power. Called from usb connect event ISR. */ |
@@ -159,5 +159,5 @@ void power_init(void) | |||
159 | & MC13783_SE1S); | 159 | & MC13783_SE1S); |
160 | 160 | ||
161 | /* Enable detect event */ | 161 | /* Enable detect event */ |
162 | mc13783_enable_event(MC13783_SE1_EVENT, true); | 162 | mc13783_enable_event(MC13783_INT_ID_SE1, true); |
163 | } | 163 | } |
diff --git a/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.h b/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.h index 9294de102c..2cd509267c 100644 --- a/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.h +++ b/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.h | |||
@@ -21,7 +21,6 @@ | |||
21 | #ifndef POWER_IMX31_H | 21 | #ifndef POWER_IMX31_H |
22 | #define POWER_IMX31_H | 22 | #define POWER_IMX31_H |
23 | 23 | ||
24 | void charger_main_detect_event(void); | ||
25 | void charger_usb_detect_event(int status); | 24 | void charger_usb_detect_event(int status); |
26 | 25 | ||
27 | #endif /* POWER_IMX31_H */ | 26 | #endif /* POWER_IMX31_H */ |
diff --git a/firmware/target/arm/imx31/gigabeat-s/usb-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/usb-gigabeat-s.c index 9129568b7a..71e8342595 100644 --- a/firmware/target/arm/imx31/gigabeat-s/usb-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/usb-gigabeat-s.c | |||
@@ -70,10 +70,10 @@ static void update_usb_status(bool sense) | |||
70 | } | 70 | } |
71 | 71 | ||
72 | /* Detect presence of USB bus - called from PMIC ISR */ | 72 | /* Detect presence of USB bus - called from PMIC ISR */ |
73 | void usb_connect_event(void) | 73 | void MC13783_EVENT_CB_USB(void) |
74 | { | 74 | { |
75 | /* Read the associated sense value */ | 75 | /* Read the associated sense value */ |
76 | update_usb_status(mc13783_event_sense(MC13783_USB_EVENT)); | 76 | update_usb_status(mc13783_event_sense()); |
77 | } | 77 | } |
78 | 78 | ||
79 | int usb_detect(void) | 79 | int usb_detect(void) |
@@ -90,7 +90,7 @@ void usb_init_device(void) | |||
90 | update_usb_status(usb_plugged()); | 90 | update_usb_status(usb_plugged()); |
91 | 91 | ||
92 | /* Enable PMIC event */ | 92 | /* Enable PMIC event */ |
93 | mc13783_enable_event(MC13783_USB_EVENT, true); | 93 | mc13783_enable_event(MC13783_INT_ID_USB, true); |
94 | } | 94 | } |
95 | 95 | ||
96 | void usb_enable(bool on) | 96 | void usb_enable(bool on) |
diff --git a/firmware/target/arm/imx31/gpio-imx31.c b/firmware/target/arm/imx31/gpio-imx31.c index e368d1ae07..7a7363be88 100644 --- a/firmware/target/arm/imx31/gpio-imx31.c +++ b/firmware/target/arm/imx31/gpio-imx31.c | |||
@@ -23,7 +23,8 @@ | |||
23 | #include "config.h" | 23 | #include "config.h" |
24 | #include "system.h" | 24 | #include "system.h" |
25 | #include "avic-imx31.h" | 25 | #include "avic-imx31.h" |
26 | #include "gpio-imx31.h" | 26 | #define DEFINE_GPIO_VECTOR_TABLE |
27 | #include "gpio-target.h" | ||
27 | 28 | ||
28 | /* UIE vector found in avic-imx31.c */ | 29 | /* UIE vector found in avic-imx31.c */ |
29 | extern void UIE_VECTOR(void); | 30 | extern void UIE_VECTOR(void); |
@@ -31,101 +32,91 @@ extern void UIE_VECTOR(void); | |||
31 | /* Event lists are allocated for the specific target */ | 32 | /* Event lists are allocated for the specific target */ |
32 | #if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) | 33 | #if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) |
33 | static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void); | 34 | static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void); |
34 | extern const struct gpio_event gpio1_events[GPIO1_NUM_EVENTS]; | ||
35 | #endif | 35 | #endif |
36 | 36 | ||
37 | #if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) | 37 | #if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) |
38 | static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void); | 38 | static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void); |
39 | extern const struct gpio_event gpio2_events[GPIO2_NUM_EVENTS]; | ||
40 | #endif | 39 | #endif |
41 | 40 | ||
42 | #if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) | 41 | #if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) |
43 | static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void); | 42 | static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void); |
44 | extern const struct gpio_event gpio3_events[GPIO3_NUM_EVENTS]; | ||
45 | #endif | 43 | #endif |
46 | 44 | ||
47 | #define DR (0x00 / sizeof (unsigned long)) /* 00h */ | 45 | static struct gpio_module_desc |
48 | #define GDIR (0x04 / sizeof (unsigned long)) /* 04h */ | ||
49 | #define PSR (0x08 / sizeof (unsigned long)) /* 08h */ | ||
50 | #define ICR (0x0C / sizeof (unsigned long)) /* 0Ch ICR1,2 */ | ||
51 | #define IMR (0x14 / sizeof (unsigned long)) /* 14h */ | ||
52 | #define ISR (0x18 / sizeof (unsigned long)) | ||
53 | |||
54 | static const struct gpio_module_desc | ||
55 | { | 46 | { |
56 | volatile unsigned long * const base; /* Module base address */ | 47 | volatile unsigned long * const base; /* Module base address */ |
57 | void (* const handler)(void); /* Interrupt function */ | 48 | void (* const handler)(void); /* Interrupt function */ |
58 | const struct gpio_event * const events; /* Event handler list */ | 49 | const struct gpio_event *events; /* Event handler list */ |
50 | unsigned long enabled; /* Enabled event mask */ | ||
59 | const uint8_t ints; /* AVIC int number */ | 51 | const uint8_t ints; /* AVIC int number */ |
60 | const uint8_t int_priority; /* AVIC int priority */ | 52 | const uint8_t int_priority; /* AVIC int priority */ |
61 | const uint8_t count; /* Number of events */ | 53 | uint8_t count; /* Number of events */ |
62 | } gpio_descs[GPIO_NUM_GPIO] = | 54 | } * const gpio_descs[] = |
63 | { | 55 | { |
64 | #if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) | 56 | #if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) |
65 | { | 57 | [GPIO1_NUM] = &(struct gpio_module_desc) { |
66 | .base = (unsigned long *)GPIO1_BASE_ADDR, | 58 | .base = (unsigned long *)GPIO1_BASE_ADDR, |
67 | .ints = INT_GPIO1, | 59 | .ints = INT_GPIO1, |
68 | .handler = GPIO1_HANDLER, | 60 | .handler = GPIO1_HANDLER, |
69 | .events = gpio1_events, | ||
70 | .count = GPIO1_NUM_EVENTS, | ||
71 | .int_priority = GPIO1_INT_PRIO | 61 | .int_priority = GPIO1_INT_PRIO |
72 | }, | 62 | }, |
73 | #endif | 63 | #endif |
74 | #if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) | 64 | #if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) |
75 | { | 65 | [GPIO2_NUM] = &(struct gpio_module_desc) { |
76 | .base = (unsigned long *)GPIO2_BASE_ADDR, | 66 | .base = (unsigned long *)GPIO2_BASE_ADDR, |
77 | .ints = INT_GPIO2, | 67 | .ints = INT_GPIO2, |
78 | .handler = GPIO2_HANDLER, | 68 | .handler = GPIO2_HANDLER, |
79 | .events = gpio2_events, | ||
80 | .count = GPIO2_NUM_EVENTS, | ||
81 | .int_priority = GPIO2_INT_PRIO | 69 | .int_priority = GPIO2_INT_PRIO |
82 | }, | 70 | }, |
83 | #endif | 71 | #endif |
84 | #if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) | 72 | #if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) |
85 | { | 73 | [GPIO3_NUM] = &(struct gpio_module_desc) { |
86 | .base = (unsigned long *)GPIO3_BASE_ADDR, | 74 | .base = (unsigned long *)GPIO3_BASE_ADDR, |
87 | .ints = INT_GPIO3, | 75 | .ints = INT_GPIO3, |
88 | .handler = GPIO3_HANDLER, | 76 | .handler = GPIO3_HANDLER, |
89 | .events = gpio3_events, | ||
90 | .count = GPIO3_NUM_EVENTS, | ||
91 | .int_priority = GPIO3_INT_PRIO, | 77 | .int_priority = GPIO3_INT_PRIO, |
92 | }, | 78 | }, |
93 | #endif | 79 | #endif |
94 | }; | 80 | }; |
95 | 81 | ||
82 | #define GPIO_MODULE_CNT ARRAYLEN(gpio_descs) | ||
83 | |||
84 | static const struct gpio_event * event_from_id( | ||
85 | const struct gpio_module_desc *desc, enum gpio_id id) | ||
86 | { | ||
87 | const struct gpio_event *events = desc->events; | ||
88 | for (unsigned int i = 0; i < desc->count; i++) | ||
89 | { | ||
90 | if (events[i].id == id) | ||
91 | return &events[i]; | ||
92 | } | ||
93 | |||
94 | return NULL; | ||
95 | } | ||
96 | |||
96 | static void gpio_call_events(enum gpio_module_number gpio) | 97 | static void gpio_call_events(enum gpio_module_number gpio) |
97 | { | 98 | { |
98 | const struct gpio_module_desc * const desc = &gpio_descs[gpio]; | 99 | const struct gpio_module_desc * const desc = gpio_descs[gpio]; |
99 | volatile unsigned long * const base = desc->base; | 100 | volatile unsigned long * const base = desc->base; |
100 | const struct gpio_event * event, *event_last; | ||
101 | 101 | ||
102 | event = desc->events; | 102 | /* Send only events that are not masked */ |
103 | event_last = event + desc->count; | 103 | unsigned long pnd = base[GPIO_ISR] & base[GPIO_IMR]; |
104 | 104 | ||
105 | /* Intersect pending and unmasked bits */ | 105 | if (pnd & ~desc->enabled) |
106 | unsigned long pnd = base[ISR] & base[IMR]; | 106 | UIE_VECTOR(); /* One or more aren't handled properly */ |
107 | 107 | ||
108 | /* Call each event handler in order */ | 108 | const struct gpio_event *event = desc->events; |
109 | /* .count is surely expected to be > 0 */ | ||
110 | do | ||
111 | { | ||
112 | unsigned long mask = event->mask; | ||
113 | 109 | ||
110 | while (pnd) | ||
111 | { | ||
112 | unsigned long mask = 1ul << (event->id % 32); | ||
114 | if (pnd & mask) | 113 | if (pnd & mask) |
115 | { | 114 | { |
116 | event->callback(); | 115 | event->callback(); |
117 | pnd &= ~mask; | 116 | pnd &= ~mask; |
118 | } | 117 | } |
119 | 118 | ||
120 | if (pnd == 0) | 119 | event++; |
121 | break; /* Teminate early if nothing more to service */ | ||
122 | } | ||
123 | while (++event < event_last); | ||
124 | |||
125 | if (pnd != 0) | ||
126 | { | ||
127 | /* One or more weren't handled */ | ||
128 | UIE_VECTOR(); | ||
129 | } | 120 | } |
130 | } | 121 | } |
131 | 122 | ||
@@ -152,69 +143,90 @@ static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void) | |||
152 | 143 | ||
153 | void INIT_ATTR gpio_init(void) | 144 | void INIT_ATTR gpio_init(void) |
154 | { | 145 | { |
155 | /* Mask-out GPIO interrupts - enable what's wanted later */ | 146 | for (unsigned int mod = 0; mod < GPIO_MODULE_CNT; mod++) |
156 | int i; | 147 | { |
157 | for (i = 0; i < GPIO_NUM_GPIO; i++) | 148 | struct gpio_module_desc * const desc = gpio_descs[mod]; |
158 | gpio_descs[i].base[IMR] = 0; | 149 | if (!desc) |
150 | continue; | ||
151 | |||
152 | /* Parse the event table per module. First contiguous run seen for a | ||
153 | * module is used. */ | ||
154 | const struct gpio_event *event = gpio_event_vector_tbl; | ||
155 | for (unsigned int i = 0; i < gpio_event_vector_tbl_len; i++, event++) | ||
156 | { | ||
157 | if (event->id / 32 == mod) | ||
158 | { | ||
159 | desc->events = event; | ||
160 | while (++desc->count < 32 && (++event)->id / 32 == mod); | ||
161 | break; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | /* Mask-out GPIO interrupts - enable what's wanted later */ | ||
166 | desc->base[GPIO_IMR] = 0; | ||
167 | } | ||
159 | } | 168 | } |
160 | 169 | ||
161 | bool gpio_enable_event(enum gpio_event_ids id) | 170 | bool gpio_enable_event(enum gpio_id id, bool enable) |
162 | { | 171 | { |
163 | const struct gpio_module_desc * const desc = &gpio_descs[id >> 5]; | 172 | unsigned int mod = id / 32; |
164 | const struct gpio_event * const event = &desc->events[id & 31]; | ||
165 | volatile unsigned long * const base = desc->base; | ||
166 | volatile unsigned long *icr; | ||
167 | unsigned long mask, line; | ||
168 | unsigned long imr; | ||
169 | int shift; | ||
170 | 173 | ||
171 | int oldlevel = disable_irq_save(); | 174 | struct gpio_module_desc * const desc = gpio_descs[mod]; |
172 | 175 | ||
173 | imr = base[IMR]; | 176 | if (mod >= GPIO_MODULE_CNT || desc == NULL) |
177 | return false; | ||
174 | 178 | ||
175 | if (imr == 0) | 179 | const struct gpio_event * const event = event_from_id(desc, id); |
176 | { | 180 | if (!event) |
177 | /* First enabled interrupt for this GPIO */ | 181 | return false; |
178 | avic_enable_int(desc->ints, INT_TYPE_IRQ, desc->int_priority, | ||
179 | desc->handler); | ||
180 | } | ||
181 | |||
182 | /* Set the line sense */ | ||
183 | line = find_first_set_bit(event->mask); | ||
184 | icr = &base[ICR + (line >> 4)]; | ||
185 | shift = 2*(line & 15); | ||
186 | mask = GPIO_SENSE_CONFIG_MASK << shift; | ||
187 | 182 | ||
188 | *icr = (*icr & ~mask) | ((event->sense << shift) & mask); | 183 | volatile unsigned long * const base = desc->base; |
184 | unsigned long num = id % 32; | ||
185 | unsigned long mask = 1ul << num; | ||
189 | 186 | ||
190 | /* Unmask the line */ | 187 | unsigned long cpsr = disable_irq_save(); |
191 | base[IMR] = imr | event->mask; | ||
192 | 188 | ||
193 | restore_irq(oldlevel); | 189 | unsigned long imr = base[GPIO_IMR]; |
194 | 190 | ||
195 | return true; | 191 | if (enable) |
196 | } | 192 | { |
193 | if (desc->enabled == 0) | ||
194 | { | ||
195 | /* First enabled interrupt for this GPIO */ | ||
196 | avic_enable_int(desc->ints, INT_TYPE_IRQ, desc->int_priority, | ||
197 | desc->handler); | ||
198 | } | ||
197 | 199 | ||
198 | void gpio_disable_event(enum gpio_event_ids id) | 200 | /* Set the line sense */ |
199 | { | 201 | if (event->sense == GPIO_SENSE_EDGE_SEL) |
200 | const struct gpio_module_desc * const desc = &gpio_descs[id >> 5]; | 202 | { |
201 | const struct gpio_event * const event = &desc->events[id & 31]; | 203 | /* Interrupt configuration register is ignored */ |
202 | volatile unsigned long * const base = desc->base; | 204 | base[GPIO_EDGE_SEL] |= mask; |
203 | unsigned long imr; | 205 | } |
206 | else | ||
207 | { | ||
208 | volatile unsigned long *icrp = &base[GPIO_ICR + num / 16]; | ||
209 | unsigned int shift = 2*(num % 16); | ||
210 | bitmod32(icrp, event->sense << shift, 0x3 << shift); | ||
211 | base[GPIO_EDGE_SEL] &= ~mask; | ||
212 | } | ||
204 | 213 | ||
205 | int oldlevel = disable_irq_save(); | 214 | /* Unmask the line */ |
215 | desc->enabled |= mask; | ||
216 | imr |= mask; | ||
217 | } | ||
218 | else | ||
219 | { | ||
220 | imr &= ~mask; | ||
221 | desc->enabled &= ~mask; | ||
206 | 222 | ||
207 | /* Remove bit from mask */ | 223 | if (desc->enabled == 0) |
208 | imr = base[IMR] & ~event->mask; | 224 | avic_disable_int(desc->ints); /* No events remain enabled */ |
225 | } | ||
209 | 226 | ||
210 | /* Mask the line */ | 227 | base[GPIO_IMR] = imr; |
211 | base[IMR] = imr; | ||
212 | 228 | ||
213 | if (imr == 0) | 229 | restore_irq(cpsr); |
214 | { | ||
215 | /* No events remain enabled */ | ||
216 | avic_disable_int(desc->ints); | ||
217 | } | ||
218 | 230 | ||
219 | restore_irq(oldlevel); | 231 | return true; |
220 | } | 232 | } |
diff --git a/firmware/target/arm/imx31/gpio-imx31.h b/firmware/target/arm/imx31/gpio-imx31.h index a1358672e8..86ca964f94 100644 --- a/firmware/target/arm/imx31/gpio-imx31.h +++ b/firmware/target/arm/imx31/gpio-imx31.h | |||
@@ -26,62 +26,193 @@ | |||
26 | #define USE_GPIO2_EVENTS (1 << 1) | 26 | #define USE_GPIO2_EVENTS (1 << 1) |
27 | #define USE_GPIO3_EVENTS (1 << 2) | 27 | #define USE_GPIO3_EVENTS (1 << 2) |
28 | 28 | ||
29 | /* Module indexes defined by which GPIO modules are used */ | 29 | /* Module logical indexes */ |
30 | enum gpio_module_number | 30 | enum gpio_module_number |
31 | { | 31 | { |
32 | __GPIO_NUM_START = -1, | 32 | GPIO1_NUM, /* ID 0..31 */ |
33 | #if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) | 33 | GPIO2_NUM, /* ID 32..63 */ |
34 | GPIO1_NUM, | 34 | GPIO3_NUM, /* ID 64..95 */ |
35 | #endif | ||
36 | #if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) | ||
37 | GPIO2_NUM, | ||
38 | #endif | ||
39 | #if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) | ||
40 | GPIO3_NUM, | ||
41 | #endif | ||
42 | GPIO_NUM_GPIO, | 35 | GPIO_NUM_GPIO, |
43 | }; | 36 | }; |
44 | 37 | ||
45 | /* Possible values for gpio interrupt line config */ | 38 | enum gpio_id |
46 | enum gpio_int_sense_enum | ||
47 | { | 39 | { |
48 | GPIO_SENSE_LOW_LEVEL = 0, /* High-level sensitive */ | 40 | /* GPIO1 */ |
49 | GPIO_SENSE_HIGH_LEVEL, /* Low-level sensitive */ | 41 | GPIO1_0_ID = 0, |
50 | GPIO_SENSE_RISING, /* Rising-edge sensitive */ | 42 | GPIO1_1_ID, |
51 | GPIO_SENSE_FALLING, /* Falling-edge sensitive */ | 43 | GPIO1_2_ID, |
44 | GPIO1_3_ID, | ||
45 | GPIO1_4_ID, | ||
46 | GPIO1_5_ID, | ||
47 | GPIO1_6_ID, | ||
48 | GPIO1_7_ID, | ||
49 | GPIO1_8_ID, | ||
50 | GPIO1_9_ID, | ||
51 | GPIO1_10_ID, | ||
52 | GPIO1_11_ID, | ||
53 | GPIO1_12_ID, | ||
54 | GPIO1_13_ID, | ||
55 | GPIO1_14_ID, | ||
56 | GPIO1_15_ID, | ||
57 | GPIO1_16_ID, | ||
58 | GPIO1_17_ID, | ||
59 | GPIO1_18_ID, | ||
60 | GPIO1_19_ID, | ||
61 | GPIO1_20_ID, | ||
62 | GPIO1_21_ID, | ||
63 | GPIO1_22_ID, | ||
64 | GPIO1_23_ID, | ||
65 | GPIO1_24_ID, | ||
66 | GPIO1_25_ID, | ||
67 | GPIO1_26_ID, | ||
68 | GPIO1_27_ID, | ||
69 | GPIO1_28_ID, | ||
70 | GPIO1_29_ID, | ||
71 | GPIO1_30_ID, | ||
72 | GPIO1_31_ID, | ||
73 | /* GPIO2 */ | ||
74 | GPIO2_0_ID = 32, | ||
75 | GPIO2_1_ID, | ||
76 | GPIO2_2_ID, | ||
77 | GPIO2_3_ID, | ||
78 | GPIO2_4_ID, | ||
79 | GPIO2_5_ID, | ||
80 | GPIO2_6_ID, | ||
81 | GPIO2_7_ID, | ||
82 | GPIO2_8_ID, | ||
83 | GPIO2_9_ID, | ||
84 | GPIO2_10_ID, | ||
85 | GPIO2_11_ID, | ||
86 | GPIO2_12_ID, | ||
87 | GPIO2_13_ID, | ||
88 | GPIO2_14_ID, | ||
89 | GPIO2_15_ID, | ||
90 | GPIO2_16_ID, | ||
91 | GPIO2_17_ID, | ||
92 | GPIO2_18_ID, | ||
93 | GPIO2_19_ID, | ||
94 | GPIO2_20_ID, | ||
95 | GPIO2_21_ID, | ||
96 | GPIO2_22_ID, | ||
97 | GPIO2_23_ID, | ||
98 | GPIO2_24_ID, | ||
99 | GPIO2_25_ID, | ||
100 | GPIO2_26_ID, | ||
101 | GPIO2_27_ID, | ||
102 | GPIO2_28_ID, | ||
103 | GPIO2_29_ID, | ||
104 | GPIO2_30_ID, | ||
105 | GPIO2_31_ID, | ||
106 | /* GPIO3 */ | ||
107 | GPIO3_0_ID = 64, | ||
108 | GPIO3_1_ID, | ||
109 | GPIO3_2_ID, | ||
110 | GPIO3_3_ID, | ||
111 | GPIO3_4_ID, | ||
112 | GPIO3_5_ID, | ||
113 | GPIO3_6_ID, | ||
114 | GPIO3_7_ID, | ||
115 | GPIO3_8_ID, | ||
116 | GPIO3_9_ID, | ||
117 | GPIO3_10_ID, | ||
118 | GPIO3_11_ID, | ||
119 | GPIO3_12_ID, | ||
120 | GPIO3_13_ID, | ||
121 | GPIO3_14_ID, | ||
122 | GPIO3_15_ID, | ||
123 | GPIO3_16_ID, | ||
124 | GPIO3_17_ID, | ||
125 | GPIO3_18_ID, | ||
126 | GPIO3_19_ID, | ||
127 | GPIO3_20_ID, | ||
128 | GPIO3_21_ID, | ||
129 | GPIO3_22_ID, | ||
130 | GPIO3_23_ID, | ||
131 | GPIO3_24_ID, | ||
132 | GPIO3_25_ID, | ||
133 | GPIO3_26_ID, | ||
134 | GPIO3_27_ID, | ||
135 | GPIO3_28_ID, | ||
136 | GPIO3_29_ID, | ||
137 | GPIO3_30_ID, | ||
138 | GPIO3_31_ID, | ||
52 | }; | 139 | }; |
53 | 140 | ||
54 | #define GPIO_SENSE_CONFIG_MASK 0x3 | 141 | /* Possible values for gpio interrupt line config */ |
142 | enum gpio_int_sense | ||
143 | { | ||
144 | GPIO_SENSE_LOW_LEVEL, /* High-level sensitive */ | ||
145 | GPIO_SENSE_HIGH_LEVEL, /* Low-level sensitive */ | ||
146 | GPIO_SENSE_RISING, /* Rising-edge sensitive */ | ||
147 | GPIO_SENSE_FALLING, /* Falling-edge sensitive */ | ||
148 | GPIO_SENSE_EDGE_SEL, /* Detect any edge */ | ||
149 | }; | ||
55 | 150 | ||
56 | /* Pending events will be called in array order which allows easy | 151 | /* Handlers will be called in declared order for a given module |
57 | * pioritization */ | 152 | Handlers of same module should be grouped together; module order |
153 | doesn't matter */ | ||
154 | #ifdef DEFINE_GPIO_VECTOR_TABLE | ||
58 | 155 | ||
59 | /* Describes a single event for a pin */ | 156 | /* Describes a single event for a pin */ |
60 | struct gpio_event | 157 | struct gpio_event |
61 | { | 158 | { |
62 | unsigned long mask; /* mask: 1 << (0...31) */ | 159 | uint8_t id; /* GPIOx_y_ID */ |
63 | enum gpio_int_sense_enum sense; /* Type of sense */ | 160 | uint8_t sense; /* GPIO_SENSE_x */ |
64 | void (*callback)(void); /* Callback function */ | 161 | void (*callback)(void); /* GPIOx_y_EVENT_CB */ |
65 | }; | 162 | }; |
66 | 163 | ||
67 | /* Module corresponding to the event ID is identified by range */ | 164 | #define GPIO_VECTOR_TBL_START() \ |
68 | enum gpio_event_bases | 165 | static FORCE_INLINE uintptr_t __gpio_event_vector_tbl(int __what) \ |
69 | { | 166 | { \ |
70 | #if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) | 167 | static const struct gpio_event __tbl[] = { |
71 | GPIO1_EVENT_FIRST = 32*GPIO1_NUM, | 168 | |
72 | #endif | 169 | #define GPIO_EVENT_VECTOR(__name, __sense) \ |
73 | #if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) | 170 | { .id = (__name##_ID), \ |
74 | GPIO2_EVENT_FIRST = 32*GPIO2_NUM, | 171 | .sense = (__sense), \ |
75 | #endif | 172 | .callback = ({ void __name##_EVENT_CB(void); \ |
76 | #if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) | 173 | __name##_EVENT_CB; }) }, |
77 | GPIO3_EVENT_FIRST = 32*GPIO3_NUM, | 174 | |
78 | #endif | 175 | #define GPIO_VECTOR_TBL_END() \ |
79 | }; | 176 | }; \ |
177 | switch (__what) \ | ||
178 | { \ | ||
179 | default: return (uintptr_t)__tbl; \ | ||
180 | case 1: return (uintptr_t)ARRAYLEN(__tbl); \ | ||
181 | } \ | ||
182 | } | ||
80 | 183 | ||
81 | #include "gpio-target.h" | 184 | #define gpio_event_vector_tbl \ |
185 | ((const struct gpio_event *)__gpio_event_vector_tbl(0)) | ||
186 | |||
187 | #define gpio_event_vector_tbl_len \ | ||
188 | ((unsigned int)__gpio_event_vector_tbl(1)) | ||
189 | |||
190 | #endif /* DEFINE_GPIO_VECTOR_TABLE */ | ||
191 | |||
192 | #define GPIO_BASE_ADDR \ | ||
193 | (volatile unsigned long * const [GPIO_NUM_GPIO]) { \ | ||
194 | (volatile unsigned long *)GPIO1_BASE_ADDR, \ | ||
195 | (volatile unsigned long *)GPIO2_BASE_ADDR, \ | ||
196 | (volatile unsigned long *)GPIO3_BASE_ADDR } | ||
197 | |||
198 | #define GPIO_DR (0x00 / sizeof (unsigned long)) /* 00h */ | ||
199 | #define GPIO_GDIR (0x04 / sizeof (unsigned long)) /* 04h */ | ||
200 | #define GPIO_PSR (0x08 / sizeof (unsigned long)) /* 08h */ | ||
201 | #define GPIO_ICR (0x0C / sizeof (unsigned long)) /* 0Ch ICR1,2 */ | ||
202 | #define GPIO_IMR (0x14 / sizeof (unsigned long)) /* 14h */ | ||
203 | #define GPIO_ISR (0x18 / sizeof (unsigned long)) /* 18h */ | ||
204 | #define GPIO_EDGE_SEL (0x1C / sizeof (unsigned long)) /* 1Ch */ | ||
82 | 205 | ||
83 | void gpio_init(void); | 206 | void gpio_init(void); |
84 | bool gpio_enable_event(enum gpio_event_ids id); | 207 | bool gpio_enable_event(enum gpio_id id, bool enable); |
85 | void gpio_disable_event(enum gpio_event_ids id); | 208 | |
209 | static FORCE_INLINE void gpio_int_clear(enum gpio_id id) | ||
210 | { GPIO_BASE_ADDR[id / 32][GPIO_ISR] = 1ul << (id % 32); } | ||
211 | |||
212 | static FORCE_INLINE void gpio_int_enable(enum gpio_id id) | ||
213 | { bitset32(&GPIO_BASE_ADDR[id / 32][GPIO_IMR], 1ul << (id % 32)); } | ||
214 | |||
215 | static FORCE_INLINE void gpio_int_disable(enum gpio_id id) | ||
216 | { bitclr32(&GPIO_BASE_ADDR[id / 32][GPIO_IMR], 1ul << (id % 32)); } | ||
86 | 217 | ||
87 | #endif /* GPIO_IMX31_H */ | 218 | #endif /* GPIO_IMX31_H */ |
diff --git a/firmware/target/arm/imx31/mc13783-imx31.c b/firmware/target/arm/imx31/mc13783-imx31.c index 627048fa54..6bf0b878f4 100644 --- a/firmware/target/arm/imx31/mc13783-imx31.c +++ b/firmware/target/arm/imx31/mc13783-imx31.c | |||
@@ -20,9 +20,9 @@ | |||
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | #include "system.h" | 21 | #include "system.h" |
22 | #include "cpu.h" | 22 | #include "cpu.h" |
23 | #include "gpio-imx31.h" | 23 | #define DEFINE_MC13783_VECTOR_TABLE |
24 | #include "mc13783.h" | ||
25 | #include "mc13783-target.h" | 24 | #include "mc13783-target.h" |
25 | #include "gpio-target.h" | ||
26 | #include "debug.h" | 26 | #include "debug.h" |
27 | #include "kernel.h" | 27 | #include "kernel.h" |
28 | 28 | ||
@@ -32,21 +32,42 @@ struct mc13783_transfer_desc | |||
32 | struct spi_transfer_desc xfer; | 32 | struct spi_transfer_desc xfer; |
33 | union | 33 | union |
34 | { | 34 | { |
35 | /* Pick _either_ data or semaphore */ | ||
35 | struct semaphore sema; | 36 | struct semaphore sema; |
36 | uint32_t data; | 37 | uint32_t data[4]; |
37 | }; | 38 | }; |
38 | }; | 39 | }; |
39 | 40 | ||
40 | extern const struct mc13783_event mc13783_events[MC13783_NUM_EVENTS]; | 41 | static uint32_t pmic_int_enb[2]; /* Enabled ints */ |
41 | extern struct spi_node mc13783_spi; | 42 | static uint32_t pmic_int_sense_enb[2]; /* Enabled sense reading */ |
43 | static struct mc13783_transfer_desc int_xfers[2]; /* ISR transfer descriptor */ | ||
44 | static const struct mc13783_event *current_event; /* Current event in callback */ | ||
45 | static bool int_restore; /* Prevent SPI callback from | ||
46 | unmasking GPIO interrupt | ||
47 | (lockout) */ | ||
42 | 48 | ||
43 | static uint32_t pmic_int_enb[2]; /* Enabled ints */ | 49 | static const struct mc13783_event * event_from_id(enum mc13783_int_ids id) |
44 | static uint32_t pmic_int_sense_enb[2]; /* Enabled sense reading */ | 50 | { |
45 | static uint32_t int_pnd_buf[2]; /* Pending ints */ | 51 | for (unsigned int i = 0; i < mc13783_event_vector_tbl_len; i++) |
46 | static uint32_t int_data_buf[4]; /* ISR data buffer */ | 52 | { |
47 | static struct spi_transfer_desc int_xfers[2]; /* ISR transfer descriptor */ | 53 | if (mc13783_event_vector_tbl[i].id == id) |
48 | static bool restore_event = true; /* Protect SPI callback from unmasking GPIO | 54 | return &mc13783_event_vector_tbl[i]; |
49 | interrupt (lockout) */ | 55 | } |
56 | |||
57 | return NULL; | ||
58 | } | ||
59 | |||
60 | /* Called when a transfer is finished and data is ready/written */ | ||
61 | static void mc13783_xfer_complete_cb(struct spi_transfer_desc *xfer) | ||
62 | { | ||
63 | semaphore_release(&((struct mc13783_transfer_desc *)xfer)->sema); | ||
64 | } | ||
65 | |||
66 | static inline bool wait_for_transfer_complete(struct mc13783_transfer_desc *xfer) | ||
67 | { | ||
68 | return semaphore_wait(&xfer->sema, TIMEOUT_BLOCK) | ||
69 | == OBJ_WAIT_SUCCEEDED && xfer->xfer.count == 0; | ||
70 | } | ||
50 | 71 | ||
51 | static inline bool mc13783_transfer(struct spi_transfer_desc *xfer, | 72 | static inline bool mc13783_transfer(struct spi_transfer_desc *xfer, |
52 | uint32_t *txbuf, | 73 | uint32_t *txbuf, |
@@ -64,90 +85,96 @@ static inline bool mc13783_transfer(struct spi_transfer_desc *xfer, | |||
64 | return spi_transfer(xfer); | 85 | return spi_transfer(xfer); |
65 | } | 86 | } |
66 | 87 | ||
67 | /* Called when a transfer is finished and data is ready/written */ | 88 | static inline void sync_transfer_init(struct mc13783_transfer_desc *xfer) |
68 | static void mc13783_xfer_complete_cb(struct spi_transfer_desc *xfer) | ||
69 | { | 89 | { |
70 | semaphore_release(&((struct mc13783_transfer_desc *)xfer)->sema); | 90 | semaphore_init(&xfer->sema, 1, 0); |
71 | } | 91 | } |
72 | 92 | ||
73 | static inline bool wait_for_transfer_complete(struct mc13783_transfer_desc *xfer) | 93 | static inline bool mc13783_sync_transfer(struct mc13783_transfer_desc *xfer, |
94 | uint32_t *txbuf, | ||
95 | uint32_t *rxbuf, | ||
96 | int count) | ||
74 | { | 97 | { |
75 | return semaphore_wait(&xfer->sema, TIMEOUT_BLOCK) | 98 | sync_transfer_init(xfer); |
76 | == OBJ_WAIT_SUCCEEDED && xfer->xfer.count == 0; | 99 | return mc13783_transfer(&xfer->xfer, txbuf, rxbuf, count, mc13783_xfer_complete_cb); |
77 | } | 100 | } |
78 | 101 | ||
79 | /* Efficient interrupt status and acking */ | 102 | /* Efficient interrupt status and acking */ |
80 | static void mc13783_int_svc_complete_callback(struct spi_transfer_desc *xfer) | 103 | static void mc13783_int_svc_complete_callback(struct spi_transfer_desc *xfer) |
81 | { | 104 | { |
105 | struct mc13783_transfer_desc *desc1 = (struct mc13783_transfer_desc *)xfer; | ||
106 | uint32_t pnd0 = desc1->data[0], pnd1 = desc1->data[1]; | ||
107 | |||
82 | /* Restore PMIC interrupt events */ | 108 | /* Restore PMIC interrupt events */ |
83 | if (restore_event) | 109 | if (int_restore) |
84 | bitset32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE); | 110 | gpio_int_enable(MC13783_EVENT_ID); |
85 | 111 | ||
86 | /* Call handlers */ | 112 | /* Call handlers */ |
87 | for ( | 113 | const struct mc13783_event *event = mc13783_event_vector_tbl; |
88 | const struct mc13783_event *event = mc13783_events; | 114 | while (pnd0 | pnd1) |
89 | int_pnd_buf[0] | int_pnd_buf[1]; | ||
90 | event++ | ||
91 | ) | ||
92 | { | 115 | { |
93 | unsigned int set = event->int_id / MC13783_INT_ID_SET_DIV; | 116 | uint32_t id = event->id; |
94 | uint32_t pnd = int_pnd_buf[set]; | 117 | uint32_t set = id / 32; |
95 | uint32_t mask = 1 << (event->int_id & MC13783_INT_ID_NUM_MASK); | 118 | uint32_t bit = 1 << (id % 32); |
96 | 119 | ||
97 | if (pnd & mask) | 120 | uint32_t pnd = set == 0 ? pnd0 : pnd1; |
121 | if (pnd & bit) | ||
98 | { | 122 | { |
123 | current_event = event; | ||
99 | event->callback(); | 124 | event->callback(); |
100 | int_pnd_buf[set] = pnd & ~mask; | 125 | set == 0 ? (pnd0 &= ~bit) : (pnd1 &= ~bit); |
101 | } | 126 | } |
102 | } | ||
103 | 127 | ||
104 | (void)xfer; | 128 | event++; |
129 | } | ||
105 | } | 130 | } |
106 | 131 | ||
107 | static void mc13783_int_svc_callback(struct spi_transfer_desc *xfer) | 132 | static void mc13783_int_svc_callback(struct spi_transfer_desc *xfer) |
108 | { | 133 | { |
109 | /* Only clear interrupts with handlers */ | 134 | /* Only clear interrupts with handlers */ |
110 | int_pnd_buf[0] &= pmic_int_enb[0]; | 135 | struct mc13783_transfer_desc *desc0 = (struct mc13783_transfer_desc *)xfer; |
111 | int_pnd_buf[1] &= pmic_int_enb[1]; | 136 | struct mc13783_transfer_desc *desc1 = &int_xfers[1]; |
112 | 137 | ||
113 | /* Only read sense if enabled interrupts have them enabled */ | 138 | uint32_t pnd0 = desc0->data[0] & pmic_int_enb[0]; |
114 | if ((int_pnd_buf[0] & pmic_int_sense_enb[0]) || | 139 | uint32_t pnd1 = desc0->data[1] & pmic_int_enb[1]; |
115 | (int_pnd_buf[1] & pmic_int_sense_enb[1])) | 140 | |
116 | { | 141 | desc1->data[0] = pnd0; |
117 | int_data_buf[2] = MC13783_INTERRUPT_SENSE0 << 25; | 142 | desc1->data[1] = pnd1; |
118 | int_data_buf[3] = MC13783_INTERRUPT_SENSE1 << 25; | ||
119 | int_xfers[1].rxbuf = int_data_buf; | ||
120 | int_xfers[1].count = 4; | ||
121 | } | ||
122 | 143 | ||
123 | /* Setup the write packets with status(es) to clear */ | 144 | /* Setup the write packets with status(es) to clear */ |
124 | int_data_buf[0] = (1 << 31) | (MC13783_INTERRUPT_STATUS0 << 25) | 145 | desc0->data[0] = (1 << 31) | (MC13783_INTERRUPT_STATUS0 << 25) | pnd0; |
125 | | int_pnd_buf[0]; | 146 | desc0->data[1] = (1 << 31) | (MC13783_INTERRUPT_STATUS1 << 25) | pnd1; |
126 | int_data_buf[1] = (1 << 31) | (MC13783_INTERRUPT_STATUS1 << 25) | 147 | |
127 | | int_pnd_buf[1]; | 148 | /* Only read sense if any pending interrupts have them enabled */ |
128 | (void)xfer; | 149 | if ((pnd0 & pmic_int_sense_enb[0]) || (pnd1 & pmic_int_sense_enb[1])) |
150 | { | ||
151 | desc0->data[2] = MC13783_INTERRUPT_SENSE0 << 25; | ||
152 | desc0->data[3] = MC13783_INTERRUPT_SENSE1 << 25; | ||
153 | desc1->xfer.rxbuf = desc0->data; | ||
154 | desc1->xfer.count = 4; | ||
155 | } | ||
129 | } | 156 | } |
130 | 157 | ||
131 | /* GPIO interrupt handler for mc13783 */ | 158 | /* GPIO interrupt handler for mc13783 */ |
132 | void mc13783_event(void) | 159 | void INT_MC13783(void) |
133 | { | 160 | { |
134 | /* Mask the interrupt (unmasked after final read services it). */ | 161 | /* Mask the interrupt (unmasked after final read services it). */ |
135 | bitclr32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE); | 162 | gpio_int_disable(MC13783_EVENT_ID); |
136 | MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE); | 163 | gpio_int_clear(MC13783_EVENT_ID); |
137 | 164 | ||
138 | /* Setup the read packets */ | 165 | /* Setup the read packets */ |
139 | int_pnd_buf[0] = MC13783_INTERRUPT_STATUS0 << 25; | 166 | int_xfers[0].data[0] = MC13783_INTERRUPT_STATUS0 << 25; |
140 | int_pnd_buf[1] = MC13783_INTERRUPT_STATUS1 << 25; | 167 | int_xfers[0].data[1] = MC13783_INTERRUPT_STATUS1 << 25; |
141 | 168 | ||
142 | unsigned long cpsr = disable_irq_save(); | 169 | unsigned long cpsr = disable_irq_save(); |
143 | 170 | ||
144 | /* Do these without intervening transfers */ | 171 | /* Do these without intervening transfers */ |
145 | if (mc13783_transfer(&int_xfers[0], int_pnd_buf, int_pnd_buf, 2, | 172 | if (mc13783_transfer(&int_xfers[0].xfer, int_xfers[0].data, |
146 | mc13783_int_svc_callback)) | 173 | int_xfers[0].data, 2, mc13783_int_svc_callback)) |
147 | { | 174 | { |
148 | /* Start this provisionally and fill-in actual values during the | 175 | /* Start this provisionally and fill-in actual values during the |
149 | first transfer's callback - set whatever could be known */ | 176 | first transfer's callback - set whatever could be known */ |
150 | mc13783_transfer(&int_xfers[1], int_data_buf, NULL, 2, | 177 | mc13783_transfer(&int_xfers[1].xfer, int_xfers[0].data, NULL, 2, |
151 | mc13783_int_svc_complete_callback); | 178 | mc13783_int_svc_complete_callback); |
152 | } | 179 | } |
153 | 180 | ||
@@ -166,43 +193,45 @@ void INIT_ATTR mc13783_init(void) | |||
166 | mc13783_write(MC13783_INTERRUPT_MASK0, 0xffffff); | 193 | mc13783_write(MC13783_INTERRUPT_MASK0, 0xffffff); |
167 | mc13783_write(MC13783_INTERRUPT_MASK1, 0xffffff); | 194 | mc13783_write(MC13783_INTERRUPT_MASK1, 0xffffff); |
168 | 195 | ||
169 | MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE); | 196 | gpio_int_clear(MC13783_EVENT_ID); |
170 | gpio_enable_event(MC13783_EVENT_ID); | 197 | gpio_enable_event(MC13783_EVENT_ID, true); |
171 | } | 198 | } |
172 | 199 | ||
173 | void mc13783_close(void) | 200 | void mc13783_close(void) |
174 | { | 201 | { |
175 | restore_event = false; | 202 | int_restore = false; |
176 | gpio_disable_event(MC13783_EVENT_ID); | 203 | gpio_int_disable(MC13783_EVENT_ID); |
204 | gpio_enable_event(MC13783_EVENT_ID, false); | ||
177 | spi_enable_node(&mc13783_spi, false); | 205 | spi_enable_node(&mc13783_spi, false); |
178 | } | 206 | } |
179 | 207 | ||
180 | void mc13783_enable_event(enum mc13783_event_ids id, bool enable) | 208 | void mc13783_enable_event(enum mc13783_int_ids id, bool enable) |
181 | { | 209 | { |
182 | static const unsigned char pmic_intm_regs[2] = | 210 | static const unsigned char pmic_intm_regs[2] = |
183 | { MC13783_INTERRUPT_MASK0, MC13783_INTERRUPT_MASK1 }; | 211 | { MC13783_INTERRUPT_MASK0, MC13783_INTERRUPT_MASK1 }; |
184 | 212 | ||
185 | const struct mc13783_event * const event = &mc13783_events[id]; | 213 | const struct mc13783_event * const event = event_from_id(id); |
186 | unsigned int set = event->int_id / MC13783_INT_ID_SET_DIV; | 214 | if (event == NULL) |
187 | uint32_t mask = 1 << (event->int_id & MC13783_INT_ID_NUM_MASK); | 215 | return; |
216 | |||
217 | unsigned int set = id / 32; | ||
218 | uint32_t mask = 1 << (id % 32); | ||
219 | uint32_t bit = enable ? mask : 0; | ||
188 | 220 | ||
189 | /* Mask GPIO while changing bits around */ | 221 | /* Mask GPIO while changing bits around */ |
190 | restore_event = false; | 222 | int_restore = false; |
191 | bitclr32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE); | 223 | gpio_int_disable(MC13783_EVENT_ID); |
192 | mc13783_write_masked(pmic_intm_regs[set], | 224 | mc13783_write_masked(pmic_intm_regs[set], bit ^ mask, mask); |
193 | enable ? 0 : mask, mask); | 225 | bitmod32(&pmic_int_sense_enb[set], event->sense ? bit : 0, mask); |
194 | bitmod32(&pmic_int_enb[set], enable ? mask : 0, mask); | 226 | bitmod32(&pmic_int_enb[set], bit, mask); |
195 | bitmod32(&pmic_int_sense_enb[set], enable ? event->sense : 0, | 227 | int_restore = true; |
196 | event->sense); | 228 | gpio_int_enable(MC13783_EVENT_ID); |
197 | restore_event = true; | ||
198 | bitset32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE); | ||
199 | } | 229 | } |
200 | 230 | ||
201 | uint32_t mc13783_event_sense(enum mc13783_event_ids id) | 231 | uint32_t mc13783_event_sense(void) |
202 | { | 232 | { |
203 | const struct mc13783_event * const event = &mc13783_events[id]; | 233 | const struct mc13783_event *event = current_event; |
204 | unsigned int set = event->int_id / MC13783_INT_ID_SET_DIV; | 234 | return int_xfers[0].data[2 + event->id / 32] & event->sense; |
205 | return int_data_buf[2 + set] & event->sense; | ||
206 | } | 235 | } |
207 | 236 | ||
208 | uint32_t mc13783_set(unsigned address, uint32_t bits) | 237 | uint32_t mc13783_set(unsigned address, uint32_t bits) |
@@ -219,8 +248,7 @@ uint32_t mc13783_clear(unsigned address, uint32_t bits) | |||
219 | static void mc13783_write_masked_cb(struct spi_transfer_desc *xfer) | 248 | static void mc13783_write_masked_cb(struct spi_transfer_desc *xfer) |
220 | { | 249 | { |
221 | struct mc13783_transfer_desc *desc = (struct mc13783_transfer_desc *)xfer; | 250 | struct mc13783_transfer_desc *desc = (struct mc13783_transfer_desc *)xfer; |
222 | uint32_t *packets = desc->xfer.rxbuf; /* Will have been advanced by 1 */ | 251 | desc->data[1] |= desc->data[0] & desc->data[2]; /* & ~mask */ |
223 | packets[0] |= packets[-1] & ~desc->data; | ||
224 | } | 252 | } |
225 | 253 | ||
226 | uint32_t mc13783_write_masked(unsigned address, uint32_t data, uint32_t mask) | 254 | uint32_t mc13783_write_masked(unsigned address, uint32_t data, uint32_t mask) |
@@ -230,28 +258,23 @@ uint32_t mc13783_write_masked(unsigned address, uint32_t data, uint32_t mask) | |||
230 | 258 | ||
231 | mask &= 0xffffff; | 259 | mask &= 0xffffff; |
232 | 260 | ||
233 | uint32_t packets[2] = | ||
234 | { | ||
235 | address << 25, | ||
236 | (1 << 31) | (address << 25) | (data & mask) | ||
237 | }; | ||
238 | |||
239 | struct mc13783_transfer_desc xfers[2]; | 261 | struct mc13783_transfer_desc xfers[2]; |
240 | xfers[0].data = mask; | 262 | xfers[0].data[0] = address << 25; |
241 | semaphore_init(&xfers[1].sema, 1, 0); | 263 | xfers[0].data[1] = (1 << 31) | (address << 25) | (data & mask); |
264 | xfers[0].data[2] = ~mask; | ||
242 | 265 | ||
243 | unsigned long cpsr = disable_irq_save(); | 266 | unsigned long cpsr = disable_irq_save(); |
244 | 267 | ||
245 | /* Queue up two transfers in a row */ | 268 | /* Queue up two transfers in a row */ |
246 | bool ok = mc13783_transfer(&xfers[0].xfer, &packets[0], &packets[0], 1, | 269 | bool ok = mc13783_transfer(&xfers[0].xfer, |
270 | &xfers[0].data[0], &xfers[0].data[0], 1, | ||
247 | mc13783_write_masked_cb) && | 271 | mc13783_write_masked_cb) && |
248 | mc13783_transfer(&xfers[1].xfer, &packets[1], NULL, 1, | 272 | mc13783_sync_transfer(&xfers[1], &xfers[0].data[1], NULL, 1); |
249 | mc13783_xfer_complete_cb); | ||
250 | 273 | ||
251 | restore_irq(cpsr); | 274 | restore_irq(cpsr); |
252 | 275 | ||
253 | if (ok && wait_for_transfer_complete(&xfers[1])) | 276 | if (ok && wait_for_transfer_complete(&xfers[1])) |
254 | return packets[0]; | 277 | return xfers[0].data[0]; |
255 | 278 | ||
256 | return MC13783_DATA_ERROR; | 279 | return MC13783_DATA_ERROR; |
257 | } | 280 | } |
@@ -264,10 +287,7 @@ uint32_t mc13783_read(unsigned address) | |||
264 | uint32_t packet = address << 25; | 287 | uint32_t packet = address << 25; |
265 | 288 | ||
266 | struct mc13783_transfer_desc xfer; | 289 | struct mc13783_transfer_desc xfer; |
267 | semaphore_init(&xfer.sema, 1, 0); | 290 | if (mc13783_sync_transfer(&xfer, &packet, &packet, 1) && |
268 | |||
269 | if (mc13783_transfer(&xfer.xfer, &packet, &packet, 1, | ||
270 | mc13783_xfer_complete_cb) && | ||
271 | wait_for_transfer_complete(&xfer)) | 291 | wait_for_transfer_complete(&xfer)) |
272 | { | 292 | { |
273 | return packet; | 293 | return packet; |
@@ -284,10 +304,7 @@ int mc13783_write(unsigned address, uint32_t data) | |||
284 | uint32_t packet = (1 << 31) | (address << 25) | (data & 0xffffff); | 304 | uint32_t packet = (1 << 31) | (address << 25) | (data & 0xffffff); |
285 | 305 | ||
286 | struct mc13783_transfer_desc xfer; | 306 | struct mc13783_transfer_desc xfer; |
287 | semaphore_init(&xfer.sema, 1, 0); | 307 | if (mc13783_sync_transfer(&xfer, &packet, NULL, 1) && |
288 | |||
289 | if (mc13783_transfer(&xfer.xfer, &packet, NULL, 1, | ||
290 | mc13783_xfer_complete_cb) && | ||
291 | wait_for_transfer_complete(&xfer)) | 308 | wait_for_transfer_complete(&xfer)) |
292 | { | 309 | { |
293 | return 1 - xfer.xfer.count; | 310 | return 1 - xfer.xfer.count; |
@@ -300,7 +317,7 @@ int mc13783_read_regs(const unsigned char *regs, uint32_t *buffer, | |||
300 | int count) | 317 | int count) |
301 | { | 318 | { |
302 | struct mc13783_transfer_desc xfer; | 319 | struct mc13783_transfer_desc xfer; |
303 | semaphore_init(&xfer.sema, 1, 0); | 320 | sync_transfer_init(&xfer); |
304 | 321 | ||
305 | if (mc13783_read_async(&xfer.xfer, regs, buffer, count, | 322 | if (mc13783_read_async(&xfer.xfer, regs, buffer, count, |
306 | mc13783_xfer_complete_cb) && | 323 | mc13783_xfer_complete_cb) && |
@@ -316,7 +333,7 @@ int mc13783_write_regs(const unsigned char *regs, uint32_t *buffer, | |||
316 | int count) | 333 | int count) |
317 | { | 334 | { |
318 | struct mc13783_transfer_desc xfer; | 335 | struct mc13783_transfer_desc xfer; |
319 | semaphore_init(&xfer.sema, 1, 0); | 336 | sync_transfer_init(&xfer); |
320 | 337 | ||
321 | if (mc13783_write_async(&xfer.xfer, regs, buffer, count, | 338 | if (mc13783_write_async(&xfer.xfer, regs, buffer, count, |
322 | mc13783_xfer_complete_cb) && | 339 | mc13783_xfer_complete_cb) && |